<commit_before>// +build !providerless

/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package azure

import (
	"testing"

	"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
	"github.com/golang/mock/gomock"

	"k8s.io/legacy-cloud-providers/azure/clients/fileclient/mockfileclient"
	"k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient"
)

func TestCreateFileShare(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	cloud := &Cloud{}
	mockFileClient := mockfileclient.NewMockInterface(ctrl)
	mockFileClient.EXPECT().CreateFileShare(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
	cloud.FileClient = mockFileClient

	name := "baz"
	sku := "sku"
	kind := "StorageV2"
	location := "centralus"
	value := "foo key"
	bogus := "bogus"

	tests := []struct {
		name     string
		acct     string
		acctType string
		acctKind string
		loc      string
		gb       int
		accounts []storage.Account
		keys     storage.AccountListKeysResult
		err      error

		expectErr  bool
		expectAcct string
		expectKey  string
	}{
		{
			name:      "foo",
			acct:      "bar",
			acctType:  "type",
			acctKind:  "StorageV2",
			loc:       "eastus",
			gb:        10,
			expectErr: true,
		},
		{
			name:      "foo",
			acct:      "",
			acctType:  "type",
			acctKind:  "StorageV2",
			loc:       "eastus",
			gb:        10,
			expectErr: true,
		},
		{
			name:     "foo",
			acct:     "",
			acctType: sku,
			acctKind: kind,
			loc:      location,
			gb:       10,
			accounts: []storage.Account{
				{Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Kind: storage.Kind(kind), Location: &location},
			},
			keys: storage.AccountListKeysResult{
				Keys: &[]storage.AccountKey{
					{Value: &value},
				},
			},
			expectAcct: "baz",
			expectKey:  "key",
		},
		{
			name:     "foo",
			acct:     "",
			acctType: sku,
			acctKind: kind,
			loc:      location,
			gb:       10,
			accounts: []storage.Account{
				{Name: &bogus, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &location},
			},
			expectErr: true,
		},
		{
			name:     "foo",
			acct:     "",
			acctType: sku,
			acctKind: kind,
			loc:      location,
			gb:       10,
			accounts: []storage.Account{
				{Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &bogus},
			},
			expectErr: true,
		},
	}

	for _, test := range tests {
		mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl)
		cloud.StorageAccountClient = mockStorageAccountsClient
		mockStorageAccountsClient.EXPECT().ListKeys(gomock.Any(), "rg", gomock.Any()).Return(test.keys, nil).AnyTimes()
		mockStorageAccountsClient.EXPECT().ListByResourceGroup(gomock.Any(), "rg").Return(test.accounts, nil).AnyTimes()
		mockStorageAccountsClient.EXPECT().Create(gomock.Any(), "rg", gomock.Any(), gomock.Any()).Return(nil).AnyTimes()

		account, key, err := cloud.CreateFileShare(test.name, test.acct, test.acctType, test.acctKind, "rg", test.loc, test.gb)
		if test.expectErr && err == nil {
			t.Errorf("unexpected non-error")
			continue
		}
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		if test.expectAcct != account {
			t.Errorf("Expected: %s, got %s", test.expectAcct, account)
		}
		if test.expectKey != key {
			t.Errorf("Expected: %s, got %s", test.expectKey, key)
		}
	}
}

func TestDeleteFileShare(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	cloud := &Cloud{}
	mockFileClient := mockfileclient.NewMockInterface(ctrl)
	mockFileClient.EXPECT().DeleteFileShare(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
	cloud.FileClient = mockFileClient

	tests := []struct {
		rg   string
		acct string
		name string

		expectErr bool
	}{
		{
			rg:   "rg",
			acct: "bar",
			name: "foo",

			expectErr: false,
		},
	}

	for _, test := range tests {
		mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl)
		cloud.StorageAccountClient = mockStorageAccountsClient

		err := cloud.DeleteFileShare(test.rg, test.acct, test.name)
		if test.expectErr && err == nil {
			t.Errorf("unexpected non-error")
			continue
		}
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
	}
}

func TestResizeFileShare(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	cloud := &Cloud{}
	mockFileClient := mockfileclient.NewMockInterface(ctrl)
	mockFileClient.EXPECT().ResizeFileShare(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
	cloud.FileClient = mockFileClient

	tests := []struct {
		rg   string
		acct string
		name string
		gb   int

		expectErr bool
	}{
		{
			rg:   "rg",
			acct: "bar",
			name: "foo",
			gb:   10,

			expectErr: false,
		},
	}

	for _, test := range tests {
		mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl)
		cloud.StorageAccountClient = mockStorageAccountsClient

		err := cloud.ResizeFileShare(test.rg, test.acct, test.name, test.gb)
		if test.expectErr && err == nil {
			t.Errorf("unexpected non-error")
			continue
		}
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
	}
}
<commit_msg>Enrich the unit tests for azure_storage<commit_after>// +build !providerless

/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package azure

import (
	"fmt"
	"testing"

	"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
	"github.com/golang/mock/gomock"

	"k8s.io/legacy-cloud-providers/azure/clients/fileclient/mockfileclient"
	"k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient"
)

func TestCreateFileShare(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	cloud := &Cloud{controllerCommon: &controllerCommon{resourceGroup: "rg"}}
	name := "baz"
	sku := "sku"
	kind := "StorageV2"
	location := "centralus"
	value := "foo key"
	bogus := "bogus"

	tests := []struct {
		rg       string
		name     string
		acct     string
		acctType string
		acctKind string
		loc      string
		gb       int
		accounts []storage.Account
		keys     storage.AccountListKeysResult
		err      error

		expectErr  bool
		expectAcct string
		expectKey  string
	}{
		{
			name:      "foo",
			acct:      "bar",
			acctType:  "type",
			acctKind:  "StorageV2",
			loc:       "eastus",
			gb:        10,
			expectErr: true,
		},
		{
			name:      "foo",
			acct:      "",
			acctType:  "type",
			acctKind:  "StorageV2",
			loc:       "eastus",
			gb:        10,
			expectErr: true,
		},
		{
			name:     "foo",
			acct:     "",
			acctType: sku,
			acctKind: kind,
			loc:      location,
			gb:       10,
			accounts: []storage.Account{
				{Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Kind: storage.Kind(kind), Location: &location},
			},
			keys: storage.AccountListKeysResult{
				Keys: &[]storage.AccountKey{
					{Value: &value},
				},
			},
			expectAcct: "baz",
			expectKey:  "key",
		},
		{
			rg:       "rg",
			name:     "foo",
			acct:     "",
			acctType: sku,
			acctKind: kind,
			loc:      location,
			gb:       10,
			accounts: []storage.Account{
				{Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Kind: storage.Kind(kind), Location: &location},
			},
			keys: storage.AccountListKeysResult{
				Keys: &[]storage.AccountKey{
					{Value: &value},
				},
			},
			err:       fmt.Errorf("create fileshare error"),
			expectErr: true,
		},
		{
			name:     "foo",
			acct:     "",
			acctType: sku,
			acctKind: kind,
			loc:      location,
			gb:       10,
			accounts: []storage.Account{
				{Name: &bogus, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &location},
			},
			expectErr: true,
		},
		{
			name:     "foo",
			acct:     "",
			acctType: sku,
			acctKind: kind,
			loc:      location,
			gb:       10,
			accounts: []storage.Account{
				{Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &bogus},
			},
			expectErr: true,
		},
	}

	for _, test := range tests {
		mockFileClient := mockfileclient.NewMockInterface(ctrl)
		cloud.FileClient = mockFileClient
		mockFileClient.EXPECT().CreateFileShare(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(test.err).AnyTimes()

		mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl)
		cloud.StorageAccountClient = mockStorageAccountsClient
		mockStorageAccountsClient.EXPECT().ListKeys(gomock.Any(), "rg", gomock.Any()).Return(test.keys, nil).AnyTimes()
		mockStorageAccountsClient.EXPECT().ListByResourceGroup(gomock.Any(), "rg").Return(test.accounts, nil).AnyTimes()
		mockStorageAccountsClient.EXPECT().Create(gomock.Any(), "rg", gomock.Any(), gomock.Any()).Return(nil).AnyTimes()

		account, key, err := cloud.CreateFileShare(test.name, test.acct, test.acctType, test.acctKind, test.rg, test.loc, test.gb)
		if test.expectErr && err == nil {
			t.Errorf("unexpected non-error")
			continue
		}
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		if test.expectAcct != account {
			t.Errorf("Expected: %s, got %s", test.expectAcct, account)
		}
		if test.expectKey != key {
			t.Errorf("Expected: %s, got %s", test.expectKey, key)
		}
	}
}

func TestDeleteFileShare(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	cloud := &Cloud{}
	tests := []struct {
		rg   string
		acct string
		name string

		err       error
		expectErr bool
	}{
		{
			rg:   "rg",
			acct: "bar",
			name: "foo",

			expectErr: false,
		},
		{
			rg:   "rg",
			acct: "bar",
			name: "",

			err:       fmt.Errorf("delete fileshare error"),
			expectErr: true,
		},
	}

	for _, test := range tests {
		mockFileClient := mockfileclient.NewMockInterface(ctrl)
		cloud.FileClient = mockFileClient
		mockFileClient.EXPECT().DeleteFileShare(gomock.Any(), gomock.Any(), gomock.Any()).Return(test.err).Times(1)

		err := cloud.DeleteFileShare(test.rg, test.acct, test.name)
		if test.expectErr && err == nil {
			t.Errorf("unexpected non-error")
			continue
		}
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
	}
}

func TestResizeFileShare(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	cloud := &Cloud{}
	mockFileClient := mockfileclient.NewMockInterface(ctrl)
	mockFileClient.EXPECT().ResizeFileShare(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
	cloud.FileClient = mockFileClient

	tests := []struct {
		rg   string
		acct string
		name string
		gb   int

		expectErr bool
	}{
		{
			rg:   "rg",
			acct: "bar",
			name: "foo",
			gb:   10,

			expectErr: false,
		},
	}

	for _, test := range tests {
		mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl)
		cloud.StorageAccountClient = mockStorageAccountsClient

		err := cloud.ResizeFileShare(test.rg, test.acct, test.name, test.gb)
		if test.expectErr && err == nil {
			t.Errorf("unexpected non-error")
			continue
		}
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
	}
}

func TestGetFileShare(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	cloud := &Cloud{}
	mockFileClient := mockfileclient.NewMockInterface(ctrl)
	mockFileClient.EXPECT().GetFileShare(gomock.Any(), gomock.Any(), gomock.Any()).Return(storage.FileShare{}, nil).AnyTimes()
	cloud.FileClient = mockFileClient

	tests := []struct {
		rg   string
		acct string
		name string

		expectErr bool
	}{
		{
			rg:   "rg",
			acct: "bar",
			name: "foo",

			expectErr: false,
		},
	}

	for _, test := range tests {
		mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl)
		cloud.StorageAccountClient = mockStorageAccountsClient

		_, err := cloud.GetFileShare(test.rg, test.acct, test.name)
		if test.expectErr && err == nil {
			t.Errorf("unexpected non-error")
			continue
		}
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/sigu-399/gojsonschema"

	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
)

type configuration struct {
	Listen              string            `json:"listen"`
	AccessLog           string            `json:"access_log"`
	ActivityLog         string            `json:"activity_log"`
	AllowedConnectPorts []int             `json:"allowed_connect_ports"`
	AllowedNetworks     []string          `json:"allowed_networks"`
	DisallowedNetworks  []string          `json:"disallowed_networks"`
	AuthRealm           string            `json:"auth_realm"`
	AuthType            string            `json:"auth_type"`
	AuthFile            string            `json:"auth_file"`
	ForwardedForHeader  string            `json:"forwarded_for_header"`
	BindIP              string            `json:"bind_ip"`
	ViaHeader           string            `json:"via_header"`
	ViaProxyName        string            `json:"via_proxy_name"`
	AddHeaders          map[string]string `json:"add_headers"`
}

const (
	defaultListenAddress      = "127.0.0.1:3128"
	defaultAllowedNetwork     = "127.0.0.1/32"
	defaultAllowedConnectPort = 443
)

func validateConfigurationFileSchema(fileName string) {
	var document interface{}
	err := json.Unmarshal([]byte(validationSchema), &document)
	if err != nil {
		log.Fatalf("Couldn't parse JSON schema: %v", err)
	}

	schema, err := gojsonschema.NewJsonSchemaDocument(document)
	if err != nil {
		log.Fatalf("Error while loading schema: %v\n", err)
	}

	data, err := os.Open(fileName)
	if err != nil {
		log.Fatalf("Couldn't open configuration file: %v", err)
	}

	buffer, err := ioutil.ReadAll(data)
	if err != nil {
		log.Fatalf("Couldn't read configuration file: %v\n", err)
	}

	var config interface{}
	err = json.Unmarshal(buffer, &config)
	if err != nil {
		log.Fatalf("Couldn't parse configuration file: %v\n", err)
	}

	result := schema.Validate(config)
	if !result.Valid() {
		fmt.Println("Configuration file is not valid:")
		// Loop through errors
		for _, desc := range result.Errors() {
			fmt.Printf(" %s\n", desc)
		}
		os.Exit(1)
	}
}

func validateNetworks(networks []string) {
	if networks != nil && len(networks) > 0 {
		for i, network := range networks {
			_, _, err := net.ParseCIDR(network)
			if err != nil {
				if ip := net.ParseIP(network); ip != nil {
					if ip4 := ip.To4(); ip4 != nil {
						networks[i] = network + "/32"
						continue
					}
					if ip16 := ip.To16(); ip16 != nil {
						networks[i] = network + "/128"
						continue
					}
				}
				log.Fatalf("couldn't parse network %s: %v", network, err)
			}
		}
	}
}

func validateIP(addr string) {
	if addr != "" {
		ip := net.ParseIP(addr)
		if ip == nil {
			log.Fatalf("incorrect IP address %s", addr)
		}
	}
}

func newConfigurationFromFile(path string) *configuration {
	file, err := os.Open(path)
	if err != nil {
		log.Fatal("can't open configuration file: ", err)
	}

	conf := newConfiguration(file)

	return conf
}

func newConfiguration(data io.Reader) *configuration {
	decoder := json.NewDecoder(data)
	conf := &configuration{}
	decoder.Decode(&conf)

	if conf.Listen == "" {
		conf.Listen = defaultListenAddress
	}

	// if no auth. enabled allow only from 127.0.0.1/32 if not deliberatly specified otherwise
	if conf.AllowedNetworks == nil || len(conf.AllowedNetworks) == 0 {
		if conf.AuthFile == "" || conf.AuthType == "" {
			conf.AllowedNetworks = make([]string, 1)
			conf.AllowedNetworks[0] = defaultAllowedNetwork
		}
	}

	validateNetworks(conf.AllowedNetworks)
	validateNetworks(conf.DisallowedNetworks)

	validateIP(conf.BindIP)

	// by default allow connect only to the https protocol port
	if conf.AllowedConnectPorts == nil || len(conf.AllowedConnectPorts) == 0 {
		conf.AllowedConnectPorts = make([]int, 1)
		conf.AllowedConnectPorts[0] = defaultAllowedConnectPort
	}

	if conf.AuthType == "" && conf.AuthFile != "" {
		log.Fatal("missed mandatoty configuration parameter 'auth_type'")
	}

	// by default set X-Forwarded-For header
	if conf.ForwardedForHeader == "" {
		conf.ForwardedForHeader = "on"
	}

	if conf.ViaHeader == "" {
		conf.ViaHeader = "on"
	}

	if conf.ViaProxyName == "" && conf.ViaHeader == "on" {
		hostname, err := os.Hostname()
		if err != nil {
			log.Fatalf("os.Hostname() failed: %v\n", err)
		}
		conf.ViaProxyName = hostname
	}

	return conf
}

const validationSchema = `
{
    "type": "object",
    "properties": {
        "listen": {
            "type": "string"
        },
        "bind_ip": {
            "type": "string"
        },
        "access_log": {
            "type": "string"
        },
        "activity_log": {
            "type": "string"
        },
        "auth_file": {
            "type": "string"
        },
        "auth_type": {
            "type": "string",
            "enum": [
                "basic",
                "digest"
            ]
        },
        "auth_realm": {
            "type": "string"
        },
        "forwarded_for_header": {
            "type": "string",
            "enum": [
                "on",
                "off",
                "delete",
                "truncate"
            ]
        },
        "via_header": {
            "type": "string",
            "enum": [
                "on",
                "off",
                "delete"
            ]
        },
        "via_proxy_name": {
            "type": "string"
        },
        "allowed_networks": {
            "items": {
                "type": "string"
            }
        },
        "disallowed_networks": {
            "items": {
                "type": "string"
            }
        },
        "allowed_connect_ports": {
            "items": {
                "type": "integer",
                "maximum": 65535,
                "minimum": 1
            }
        },
        "add_headers": {
            "type": "object",
            "patternProperties": {
                "^*": {
                    "type": "string"
                }
            }
        }
    },
    "additionalProperties": false
}

`
<commit_msg>imports updates from sigu-339 to xeipuuv github account<commit_after>package main

import (
	"github.com/xeipuuv/gojsonschema"

	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
)

type configuration struct {
	Listen              string            `json:"listen"`
	AccessLog           string            `json:"access_log"`
	ActivityLog         string            `json:"activity_log"`
	AllowedConnectPorts []int             `json:"allowed_connect_ports"`
	AllowedNetworks     []string          `json:"allowed_networks"`
	DisallowedNetworks  []string          `json:"disallowed_networks"`
	AuthRealm           string            `json:"auth_realm"`
	AuthType            string            `json:"auth_type"`
	AuthFile            string            `json:"auth_file"`
	ForwardedForHeader  string            `json:"forwarded_for_header"`
	BindIP              string            `json:"bind_ip"`
	ViaHeader           string            `json:"via_header"`
	ViaProxyName        string            `json:"via_proxy_name"`
	AddHeaders          map[string]string `json:"add_headers"`
}

const (
	defaultListenAddress      = "127.0.0.1:3128"
	defaultAllowedNetwork     = "127.0.0.1/32"
	defaultAllowedConnectPort = 443
)

func validateConfigurationFileSchema(fileName string) {
	var document interface{}
	err := json.Unmarshal([]byte(validationSchema), &document)
	if err != nil {
		log.Fatalf("Couldn't parse JSON schema: %v", err)
	}

	schema, err := gojsonschema.NewJsonSchemaDocument(document)
	if err != nil {
		log.Fatalf("Error while loading schema: %v\n", err)
	}

	data, err := os.Open(fileName)
	if err != nil {
		log.Fatalf("Couldn't open configuration file: %v", err)
	}

	buffer, err := ioutil.ReadAll(data)
	if err != nil {
		log.Fatalf("Couldn't read configuration file: %v\n", err)
	}

	var config interface{}
	err = json.Unmarshal(buffer, &config)
	if err != nil {
		log.Fatalf("Couldn't parse configuration file: %v\n", err)
	}

	result := schema.Validate(config)
	if !result.Valid() {
		fmt.Println("Configuration file is not valid:")
		// Loop through errors
		for _, desc := range result.Errors() {
			fmt.Printf(" %s\n", desc)
		}
		os.Exit(1)
	}
}

func validateNetworks(networks []string) {
	if networks != nil && len(networks) > 0 {
		for i, network := range networks {
			_, _, err := net.ParseCIDR(network)
			if err != nil {
				if ip := net.ParseIP(network); ip != nil {
					if ip4 := ip.To4(); ip4 != nil {
						networks[i] = network + "/32"
						continue
					}
					if ip16 := ip.To16(); ip16 != nil {
						networks[i] = network + "/128"
						continue
					}
				}
				log.Fatalf("couldn't parse network %s: %v", network, err)
			}
		}
	}
}

func validateIP(addr string) {
	if addr != "" {
		ip := net.ParseIP(addr)
		if ip == nil {
			log.Fatalf("incorrect IP address %s", addr)
		}
	}
}

func newConfigurationFromFile(path string) *configuration {
	file, err := os.Open(path)
	if err != nil {
		log.Fatal("can't open configuration file: ", err)
	}

	conf := newConfiguration(file)

	return conf
}

func newConfiguration(data io.Reader) *configuration {
	decoder := json.NewDecoder(data)
	conf := &configuration{}
	decoder.Decode(&conf)

	if conf.Listen == "" {
		conf.Listen = defaultListenAddress
	}

	// if no auth. enabled allow only from 127.0.0.1/32 if not deliberatly specified otherwise
	if conf.AllowedNetworks == nil || len(conf.AllowedNetworks) == 0 {
		if conf.AuthFile == "" || conf.AuthType == "" {
			conf.AllowedNetworks = make([]string, 1)
			conf.AllowedNetworks[0] = defaultAllowedNetwork
		}
	}

	validateNetworks(conf.AllowedNetworks)
	validateNetworks(conf.DisallowedNetworks)

	validateIP(conf.BindIP)

	// by default allow connect only to the https protocol port
	if conf.AllowedConnectPorts == nil || len(conf.AllowedConnectPorts) == 0 {
		conf.AllowedConnectPorts = make([]int, 1)
		conf.AllowedConnectPorts[0] = defaultAllowedConnectPort
	}

	if conf.AuthType == "" && conf.AuthFile != "" {
		log.Fatal("missed mandatoty configuration parameter 'auth_type'")
	}

	// by default set X-Forwarded-For header
	if conf.ForwardedForHeader == "" {
		conf.ForwardedForHeader = "on"
	}

	if conf.ViaHeader == "" {
		conf.ViaHeader = "on"
	}

	if conf.ViaProxyName == "" && conf.ViaHeader == "on" {
		hostname, err := os.Hostname()
		if err != nil {
			log.Fatalf("os.Hostname() failed: %v\n", err)
		}
		conf.ViaProxyName = hostname
	}

	return conf
}

const validationSchema = `
{
    "type": "object",
    "properties": {
        "listen": {
            "type": "string"
        },
        "bind_ip": {
            "type": "string"
        },
        "access_log": {
            "type": "string"
        },
        "activity_log": {
            "type": "string"
        },
        "auth_file": {
            "type": "string"
        },
        "auth_type": {
            "type": "string",
            "enum": [
                "basic",
                "digest"
            ]
        },
        "auth_realm": {
            "type": "string"
        },
        "forwarded_for_header": {
            "type": "string",
            "enum": [
                "on",
                "off",
                "delete",
                "truncate"
            ]
        },
        "via_header": {
            "type": "string",
            "enum": [
                "on",
                "off",
                "delete"
            ]
        },
        "via_proxy_name": {
            "type": "string"
        },
        "allowed_networks": {
            "items": {
                "type": "string"
            }
        },
        "disallowed_networks": {
            "items": {
                "type": "string"
            }
        },
        "allowed_connect_ports": {
            "items": {
                "type": "integer",
                "maximum": 65535,
                "minimum": 1
            }
        },
        "add_headers": {
            "type": "object",
            "patternProperties": {
                "^*": {
                    "type": "string"
                }
            }
        }
    },
    "additionalProperties": false
}

`
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License Version 2.0
 * which accompanies this distribution, and is available at
 * http://www.apache.org/licenses/
 *
 * See the Apache Licence for more details.
 *
 * Contributors:
 *     nuxeo.io Team
 */

package main

import (
	"errors"
	"github.com/coreos/go-etcd/etcd"
	"github.com/golang/glog"
	"strings"
	"regexp"
	"flag"
)

type Config struct {
	servicePrefix        string
	etcdAddress          string
	cronDuration         string
	passiveLimitDuration string
	client        *etcd.Client
}

func (c *Config) getEtcdClient() (*etcd.Client, error) {
	if c.client == nil {
		c.client = etcd.NewClient([]string{c.etcdAddress})
		if !c.client.SyncCluster() {
			return nil, errors.New("Unable to sync with etcd cluster, check your configuration or etcd status")
		}
	}
	return c.client, nil
}

func (c *Config) getServiceForNode(node *etcd.Node, config *Config) string {
	r := regexp.MustCompile(config.servicePrefix + "/(.*)(/.*)*")
	return strings.Split(r.FindStringSubmatch(node.Key)[1], "/")[0]
}

func (c *Config) getServiceIndexForNode(node *etcd.Node, config *Config) string {
	r := regexp.MustCompile(config.servicePrefix + "/(.*)(/.*)*")
	return strings.Split(r.FindStringSubmatch(node.Key)[1], "/")[1]
}

func parseConfig() *Config {
	config := &Config{}
	flag.StringVar(&config.servicePrefix, "serviceDir", "/services", "etcd prefix to get services")
	flag.StringVar(&config.etcdAddress, "etcdAddress", "http://127.0.0.1:4001/", "etcd client host")
	flag.StringVar(&config.cronDuration, "cronDuration", "5", "Passivation cron checking duration ")
	flag.StringVar(&config.passiveLimitDuration, "passiveLimitDuration", "12", "Limit duration of passivation")
	flag.Parse()

	glog.Infof("Dumping Configuration")
	glog.Infof("  servicesPrefix : %s", config.servicePrefix)
	glog.Infof("  etcdAddress : %s", config.etcdAddress)
	glog.Infof("  Passivation cron duration: %s", config.cronDuration)
	glog.Infof("  Limit duration of passivation : %s", config.passiveLimitDuration)

	return config
}

<commit_msg>cosmit<commit_after>/*
 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License Version 2.0
 * which accompanies this distribution, and is available at
 * http://www.apache.org/licenses/
 *
 * See the Apache Licence for more details.
 *
 * Contributors:
 *     nuxeo.io Team
 */

package main

import (
	"errors"
	"github.com/coreos/go-etcd/etcd"
	"github.com/golang/glog"
	"strings"
	"regexp"
	"flag"
)

type Config struct {
	servicePrefix        string
	etcdAddress          string
	cronDuration         string
	passiveLimitDuration string
	client        *etcd.Client
}

func (c *Config) getEtcdClient() (*etcd.Client, error) {
	if c.client == nil {
		c.client = etcd.NewClient([]string{c.etcdAddress})
		if !c.client.SyncCluster() {
			return nil, errors.New("Unable to sync with etcd cluster, check your configuration or etcd status")
		}
	}
	return c.client, nil
}

func (c *Config) getServiceForNode(node *etcd.Node, config *Config) string {
	r := regexp.MustCompile(config.servicePrefix + "/(.*)(/.*)*")
	return strings.Split(r.FindStringSubmatch(node.Key)[1], "/")[0]
}

func (c *Config) getServiceIndexForNode(node *etcd.Node, config *Config) string {
	r := regexp.MustCompile(config.servicePrefix + "/(.*)(/.*)*")
	return strings.Split(r.FindStringSubmatch(node.Key)[1], "/")[1]
}

func parseConfig() *Config {
	config := &Config{}
	flag.StringVar(&config.servicePrefix, "serviceDir", "/services", "etcd prefix to get services")
	flag.StringVar(&config.etcdAddress, "etcdAddress", "http://127.0.0.1:4001/", "etcd client host")
	flag.StringVar(&config.cronDuration, "cronDuration", "5", "Passivation cron checking duration ")
	flag.StringVar(&config.passiveLimitDuration, "passiveLimitDuration", "12", "Limit duration of passivation")
	flag.Parse()

	glog.Infof("Dumping Configuration")
	glog.Infof("  servicesPrefix : %s", config.servicePrefix)
	glog.Infof("  etcdAddress : %s", config.etcdAddress)
	glog.Infof("  Passivation check cron duration: %s", config.cronDuration)
	glog.Infof("  Passivation time laps: %s", config.passiveLimitDuration)

	return config
}

<|endoftext|>


<commit_before>package peco

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/nsf/termbox-go"
)

var homedirFunc = homedir

// Config holds all the data that can be configured in the
// external configuran file
type Config struct {
	Action        map[string][]string `json:"Action"`
	// Keymap used to be directly responsible for dispatching
	// events against user input, but since then this has changed
	// into something that just records the user's config input
	Keymap        map[string]string `json:"Keymap"`
	Matcher       string   `json:"Matcher"`
	Style         StyleSet `json:"Style"`
	CustomMatcher map[string][]string
	Prompt        string   `json:"Prompt"`
}

// NewConfig creates a new Config
func NewConfig() *Config {
	return &Config{
		Keymap:  make(map[string]string),
		Matcher: IgnoreCaseMatch,
		Style:   NewStyleSet(),
		Prompt:  "QUERY>",
	}
}

// ReadFilename reads the config from the given file, and
// does the appropriate processing, if any
func (c *Config) ReadFilename(filename string) error {
	f, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(c)
	if err != nil {
		return err
	}

	return nil
}

var (
	stringToFg = map[string]termbox.Attribute{
		"default": termbox.ColorDefault,
		"black":   termbox.ColorBlack,
		"red":     termbox.ColorRed,
		"green":   termbox.ColorGreen,
		"yellow":  termbox.ColorYellow,
		"blue":    termbox.ColorBlue,
		"magenta": termbox.ColorMagenta,
		"cyan":    termbox.ColorCyan,
		"white":   termbox.ColorWhite,
	}
	stringToBg = map[string]termbox.Attribute{
		"on_default": termbox.ColorDefault,
		"on_black":   termbox.ColorBlack,
		"on_red":     termbox.ColorRed,
		"on_green":   termbox.ColorGreen,
		"on_yellow":  termbox.ColorYellow,
		"on_blue":    termbox.ColorBlue,
		"on_magenta": termbox.ColorMagenta,
		"on_cyan":    termbox.ColorCyan,
		"on_white":   termbox.ColorWhite,
	}
	stringToFgAttr = map[string]termbox.Attribute{
		"bold":      termbox.AttrBold,
		"underline": termbox.AttrUnderline,
		"reverse":   termbox.AttrReverse,
	}
	stringToBgAttr = map[string]termbox.Attribute{
		"on_bold": termbox.AttrBold,
	}
)

// StyleSet holds styles for various sections
type StyleSet struct {
	Basic          Style `json:"Basic"`
	SavedSelection Style `json:"SavedSelection"`
	Selected       Style `json:"Selected"`
	Query          Style `json:"Query"`
	Matched        Style `json:"Matched"`
}

// NewStyleSet creates a new StyleSet struct
func NewStyleSet() StyleSet {
	return StyleSet{
		Basic:          Style{fg: termbox.ColorDefault, bg: termbox.ColorDefault},
		SavedSelection: Style{fg: termbox.ColorBlack | termbox.AttrBold, bg: termbox.ColorCyan},
		Selected:       Style{fg: termbox.ColorDefault | termbox.AttrUnderline, bg: termbox.ColorMagenta},
		Query:          Style{fg: termbox.ColorDefault, bg: termbox.ColorDefault},
		Matched:        Style{fg: termbox.ColorCyan, bg: termbox.ColorDefault},
	}
}

// Style describes termbox styles
type Style struct {
	fg termbox.Attribute
	bg termbox.Attribute
}

// UnmarshalJSON satisfies json.RawMessage.
func (s *Style) UnmarshalJSON(buf []byte) error {
	raw := []string{}
	if err := json.Unmarshal(buf, &raw); err != nil {
		return err
	}
	*s = *stringsToStyle(raw)
	return nil
}

func stringsToStyle(raw []string) *Style {
	style := &Style{
		fg: termbox.ColorDefault,
		bg: termbox.ColorDefault,
	}

	for _, s := range raw {
		fg, ok := stringToFg[s]
		if ok {
			style.fg = fg
		}

		bg, ok := stringToBg[s]
		if ok {
			style.bg = bg
		}
	}

	for _, s := range raw {
		fg_attr, ok := stringToFgAttr[s]
		if ok {
			style.fg |= fg_attr
		}

		bg_attr, ok := stringToBgAttr[s]
		if ok {
			style.bg |= bg_attr
		}
	}

	return style
}

var _locateRcfileIn = locateRcfileIn

func locateRcfileIn(dir string) (string, error) {
	const basename = "config.json"
	file := filepath.Join(dir, basename)
	if _, err := os.Stat(file); err != nil {
		return "", err
	}
	return file, nil
}

// LocateRcfile attempts to find the config file in various locations
func LocateRcfile() (string, error) {
	// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
	//
	// Try in this order:
	//	  $XDG_CONFIG_HOME/peco/config.json
	//    $XDG_CONFIG_DIR/peco/config.json (where XDG_CONFIG_DIR is listed in $XDG_CONFIG_DIRS)
	//	  ~/.peco/config.json

	home, uErr := homedirFunc()

	// Try dir supplied via env var
	if dir := os.Getenv("XDG_CONFIG_HOME"); dir != "" {
		file, err := _locateRcfileIn(filepath.Join(dir, "peco"))
		if err == nil {
			return file, nil
		}
	} else if uErr == nil { // silently ignore failure for homedir()
		// Try "default" XDG location, is user is available
		file, err := _locateRcfileIn(filepath.Join(home, ".config", "peco"))
		if err == nil {
			return file, nil
		}
	}

	// this standard does not take into consideration windows (duh)
	// while the spec says use ":" as the separator, Go provides us
	// with filepath.ListSeparator, so use it
	if dirs := os.Getenv("XDG_CONFIG_DIRS"); dirs != "" {
		for _, dir := range strings.Split(dirs, fmt.Sprintf("%c", filepath.ListSeparator)) {
			file, err := _locateRcfileIn(filepath.Join(dir, "peco"))
			if err == nil {
				return file, nil
			}
		}
	}

	if uErr == nil { // silently ignore failure for homedir()
		file, err := _locateRcfileIn(filepath.Join(home, ".peco"))
		if err == nil {
			return file, nil
		}
	}

	return "", fmt.Errorf("error: Config file not found")
}
<commit_msg>golint<commit_after>package peco

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/nsf/termbox-go"
)

var homedirFunc = homedir

// Config holds all the data that can be configured in the
// external configuran file
type Config struct {
	Action        map[string][]string `json:"Action"`
	// Keymap used to be directly responsible for dispatching
	// events against user input, but since then this has changed
	// into something that just records the user's config input
	Keymap        map[string]string `json:"Keymap"`
	Matcher       string   `json:"Matcher"`
	Style         StyleSet `json:"Style"`
	CustomMatcher map[string][]string
	Prompt        string   `json:"Prompt"`
}

// NewConfig creates a new Config
func NewConfig() *Config {
	return &Config{
		Keymap:  make(map[string]string),
		Matcher: IgnoreCaseMatch,
		Style:   NewStyleSet(),
		Prompt:  "QUERY>",
	}
}

// ReadFilename reads the config from the given file, and
// does the appropriate processing, if any
func (c *Config) ReadFilename(filename string) error {
	f, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(c)
	if err != nil {
		return err
	}

	return nil
}

var (
	stringToFg = map[string]termbox.Attribute{
		"default": termbox.ColorDefault,
		"black":   termbox.ColorBlack,
		"red":     termbox.ColorRed,
		"green":   termbox.ColorGreen,
		"yellow":  termbox.ColorYellow,
		"blue":    termbox.ColorBlue,
		"magenta": termbox.ColorMagenta,
		"cyan":    termbox.ColorCyan,
		"white":   termbox.ColorWhite,
	}
	stringToBg = map[string]termbox.Attribute{
		"on_default": termbox.ColorDefault,
		"on_black":   termbox.ColorBlack,
		"on_red":     termbox.ColorRed,
		"on_green":   termbox.ColorGreen,
		"on_yellow":  termbox.ColorYellow,
		"on_blue":    termbox.ColorBlue,
		"on_magenta": termbox.ColorMagenta,
		"on_cyan":    termbox.ColorCyan,
		"on_white":   termbox.ColorWhite,
	}
	stringToFgAttr = map[string]termbox.Attribute{
		"bold":      termbox.AttrBold,
		"underline": termbox.AttrUnderline,
		"reverse":   termbox.AttrReverse,
	}
	stringToBgAttr = map[string]termbox.Attribute{
		"on_bold": termbox.AttrBold,
	}
)

// StyleSet holds styles for various sections
type StyleSet struct {
	Basic          Style `json:"Basic"`
	SavedSelection Style `json:"SavedSelection"`
	Selected       Style `json:"Selected"`
	Query          Style `json:"Query"`
	Matched        Style `json:"Matched"`
}

// NewStyleSet creates a new StyleSet struct
func NewStyleSet() StyleSet {
	return StyleSet{
		Basic:          Style{fg: termbox.ColorDefault, bg: termbox.ColorDefault},
		SavedSelection: Style{fg: termbox.ColorBlack | termbox.AttrBold, bg: termbox.ColorCyan},
		Selected:       Style{fg: termbox.ColorDefault | termbox.AttrUnderline, bg: termbox.ColorMagenta},
		Query:          Style{fg: termbox.ColorDefault, bg: termbox.ColorDefault},
		Matched:        Style{fg: termbox.ColorCyan, bg: termbox.ColorDefault},
	}
}

// Style describes termbox styles
type Style struct {
	fg termbox.Attribute
	bg termbox.Attribute
}

// UnmarshalJSON satisfies json.RawMessage.
func (s *Style) UnmarshalJSON(buf []byte) error {
	raw := []string{}
	if err := json.Unmarshal(buf, &raw); err != nil {
		return err
	}
	*s = *stringsToStyle(raw)
	return nil
}

func stringsToStyle(raw []string) *Style {
	style := &Style{
		fg: termbox.ColorDefault,
		bg: termbox.ColorDefault,
	}

	for _, s := range raw {
		fg, ok := stringToFg[s]
		if ok {
			style.fg = fg
		}

		bg, ok := stringToBg[s]
		if ok {
			style.bg = bg
		}
	}

	for _, s := range raw {
		if fgAttr, ok := stringToFgAttr[s]; ok {
			style.fg |= fgAttr
		}

		if bgAttr, ok := stringToBgAttr[s]; ok {
			style.bg |= bgAttr
		}
	}

	return style
}

var _locateRcfileIn = locateRcfileIn

func locateRcfileIn(dir string) (string, error) {
	const basename = "config.json"
	file := filepath.Join(dir, basename)
	if _, err := os.Stat(file); err != nil {
		return "", err
	}
	return file, nil
}

// LocateRcfile attempts to find the config file in various locations
func LocateRcfile() (string, error) {
	// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
	//
	// Try in this order:
	//	  $XDG_CONFIG_HOME/peco/config.json
	//    $XDG_CONFIG_DIR/peco/config.json (where XDG_CONFIG_DIR is listed in $XDG_CONFIG_DIRS)
	//	  ~/.peco/config.json

	home, uErr := homedirFunc()

	// Try dir supplied via env var
	if dir := os.Getenv("XDG_CONFIG_HOME"); dir != "" {
		file, err := _locateRcfileIn(filepath.Join(dir, "peco"))
		if err == nil {
			return file, nil
		}
	} else if uErr == nil { // silently ignore failure for homedir()
		// Try "default" XDG location, is user is available
		file, err := _locateRcfileIn(filepath.Join(home, ".config", "peco"))
		if err == nil {
			return file, nil
		}
	}

	// this standard does not take into consideration windows (duh)
	// while the spec says use ":" as the separator, Go provides us
	// with filepath.ListSeparator, so use it
	if dirs := os.Getenv("XDG_CONFIG_DIRS"); dirs != "" {
		for _, dir := range strings.Split(dirs, fmt.Sprintf("%c", filepath.ListSeparator)) {
			file, err := _locateRcfileIn(filepath.Join(dir, "peco"))
			if err == nil {
				return file, nil
			}
		}
	}

	if uErr == nil { // silently ignore failure for homedir()
		file, err := _locateRcfileIn(filepath.Join(home, ".peco"))
		if err == nil {
			return file, nil
		}
	}

	return "", fmt.Errorf("error: Config file not found")
}
<|endoftext|>


<commit_before>package gnosis

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"sync"
)

var staticConfig *Config
var configLock = new(sync.RWMutex)

type GlobalSection struct {
	Port     string
	Hostname string
}

type ServerSection struct {
	Path        string
	Prefix      string
	DefaultPage string
	ServerType  string
	Restricted  []string
}

type Config struct {
	Global     GlobalSection
	Mainserver ServerSection
	Server     []ServerSection
}

var defaultConfig = `{
  "Global": {
    "Port": "8080",
    "Hostname": "localhost"
  },
  "MainServer": {
      "Path": "/var/www/wiki/",
      "Prefix": "/",
      "Default": "index",
      "ServerType": "markdown",
      "Restricted": [
        "internal",
        "handbook"
      ]
    },
  "Server": [
  ]
}`

func GetConfig() *Config {
	configLock.RLock()
	defer configLock.RUnlock()
	return staticConfig
}

func LoadConfig(configFile string) bool {

	if configFile == "" {
		log.Println("no configuration file specified, using ./config.json")
		// return an empty config file
		configFile = "config.json"
	}

	// have to read in the line into a byte[] array
	fileContents, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Printf("Problem loading config file: %s", err.Error())
	}

	// UnMarshal the config file that was read in
	temp := new(Config)

	err = json.Unmarshal(defaultConfig, temp)

	if err != nil {
		log.Println("problem parsing built in default configuration - this should not happen")
		return false
	}

	err = json.Unmarshal(fileContents, temp)
	//Make sure you were able to read it in
	if err != nil {
		log.Printf("parse config error: %s", err.Error())
		return false
	}

	configLock.Lock()
	staticConfig = temp
	configLock.Unlock()

	return true
}
<commit_msg>forgot to convert defaultConfig to byte - did that<commit_after>package gnosis

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"sync"
)

var staticConfig *Config
var configLock = new(sync.RWMutex)

type GlobalSection struct {
	Port     string
	Hostname string
}

type ServerSection struct {
	Path        string
	Prefix      string
	DefaultPage string
	ServerType  string
	Restricted  []string
}

type Config struct {
	Global     GlobalSection
	Mainserver ServerSection
	Server     []ServerSection
}

var defaultConfig = []byte(`{
  "Global": {
    "Port": "8080",
    "Hostname": "localhost"
  },
  "MainServer": {
      "Path": "/var/www/wiki/",
      "Prefix": "/",
      "Default": "index",
      "ServerType": "markdown",
      "Restricted": [
        "internal",
        "handbook"
      ]
    },
  "Server": [
  ]
}`)

func GetConfig() *Config {
	configLock.RLock()
	defer configLock.RUnlock()
	return staticConfig
}

func LoadConfig(configFile string) bool {

	if configFile == "" {
		log.Println("no configuration file specified, using ./config.json")
		// return an empty config file
		configFile = "config.json"
	}

	// have to read in the line into a byte[] array
	fileContents, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Printf("Problem loading config file: %s", err.Error())
	}

	// UnMarshal the config file that was read in
	temp := new(Config)

	err = json.Unmarshal(defaultConfig, temp)

	if err != nil {
		log.Println("problem parsing built in default configuration - this should not happen")
		return false
	}

	err = json.Unmarshal(fileContents, temp)
	//Make sure you were able to read it in
	if err != nil {
		log.Printf("parse config error: %s", err.Error())
		return false
	}

	configLock.Lock()
	staticConfig = temp
	configLock.Unlock()

	return true
}
<|endoftext|>


<commit_before>// Copyright 2016 Mesosphere, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"github.com/dcos/dcos-go/dcos"
	"github.com/dcos/dcos-go/dcos/nodeutil"
	"github.com/dcos/dcos-metrics/collectors"
	"github.com/dcos/dcos-metrics/collectors/framework"
	mesosAgent "github.com/dcos/dcos-metrics/collectors/mesos/agent"
	"github.com/dcos/dcos-metrics/collectors/node"
	httpProducer "github.com/dcos/dcos-metrics/producers/http"
	httpClient "github.com/dcos/dcos-metrics/util/http/client"
	httpHelpers "github.com/dcos/dcos-metrics/util/http/helpers"

	log "github.com/Sirupsen/logrus"
	yaml "gopkg.in/yaml.v2"
)

var (
	// VERSION set by $(git describe --always)
	// Set by scripts/build.sh, executed by `make build`
	VERSION = "unset"
	// REVISION set by $(git rev-parse --shore HEAD)
	// Set by scripts/build.sh, executed by `make build`
	REVISION = "unset"
)

// Config defines the top-level configuration options for the dcos-metrics-collector project.
// It is (currently) broken up into two main sections: collectors and producers.
type Config struct {
	// Config from the service config file
	Collector         CollectorConfig `yaml:"collector"`
	Producers         ProducersConfig `yaml:"producers"`
	IAMConfigPath     string          `yaml:"iam_config_path"`
	CACertificatePath string          `yaml:"ca_certificate_path"`

	// Node info
	nodeInfo collectors.NodeInfo

	// Flag configuration
	DCOSRole    string
	ConfigPath  string
	LogLevel    string
	VersionFlag bool
}

// CollectorConfig contains configuration options relevant to the "collector"
// portion of this project. That is, the code responsible for querying Mesos,
// et. al to gather metrics and send them to a "producer".
type CollectorConfig struct {
	HTTPProfiler bool                  `yaml:"http_profiler"`
	Framework    *framework.Collector  `yaml:"framework,omitempty"`
	Node         *node.Collector       `yaml:"node,omitempty"`
	MesosAgent   *mesosAgent.Collector `yaml:"mesos_agent,omitempty"`
}

// ProducersConfig contains references to other structs that provide individual producer configs.
// The configuration for all producers is then located in their corresponding packages.
//
// For example: Config.Producers.KafkaProducerConfig references kafkaProducer.Config. This struct
// contains an optional Kafka configuration. This configuration is available in the source file
// 'producers/kafka/kafka.go'. It is then the responsibility of the individual producers to
// validate the configuration the user has provided and panic if necessary.
type ProducersConfig struct {
	HTTPProducerConfig httpProducer.Config `yaml:"http,omitempty"`
	//KafkaProducerConfig  kafkaProducer.Config  `yaml:"kafka,omitempty"`
	//StatsdProducerConfig statsdProducer.Config `yaml:"statsd,omitempty"`
}

func (c *Config) setFlags(fs *flag.FlagSet) {
	fs.StringVar(&c.ConfigPath, "config", c.ConfigPath, "The path to the config file.")
	fs.StringVar(&c.LogLevel, "loglevel", c.LogLevel, "Logging level (default: info). Must be one of: debug, info, warn, error, fatal, panic.")
	fs.StringVar(&c.DCOSRole, "role", c.DCOSRole, "The DC/OS role this instance runs on.")
	fs.BoolVar(&c.VersionFlag, "version", c.VersionFlag, "Print version and revsion then exit")
}

func (c *Config) loadConfig() error {
	fileByte, err := ioutil.ReadFile(c.ConfigPath)
	if err != nil {
		return err
	}

	if err = yaml.Unmarshal(fileByte, &c); err != nil {
		return err
	}

	return nil
}

func (c *Config) getNodeInfo() error {
	log.Debug("Getting node info")
	client, err := httpHelpers.NewMetricsClient(c.CACertificatePath, c.IAMConfigPath)
	if err != nil {
		return err
	}

	// Create a new DC/OS nodeutil instance
	var stateURL = "http://leader.mesos:5050/state"
	if len(c.IAMConfigPath) > 0 {
		stateURL = "https://leader.mesos:5050/state"
	}
	node, err := nodeutil.NewNodeInfo(client, c.DCOSRole, nodeutil.OptionMesosStateURL(stateURL))
	if err != nil {
		return fmt.Errorf("error: could not get nodeInfo: %s", err)
	}

	// Get node IP address
	ip, err := node.DetectIP()
	if err != nil {
		return fmt.Errorf("error: could not detect node IP: %s", err)
	}
	c.nodeInfo.IPAddress = ip.String()
	c.nodeInfo.Hostname = c.nodeInfo.IPAddress // TODO(roger): need hostname support in nodeutil

	// Get Mesos master/agent ID
	mid, err := node.MesosID(nil)
	if err != nil {
		return fmt.Errorf("error: could not get Mesos node ID: %s", err)
	}
	c.nodeInfo.MesosID = mid

	// Get cluster ID
	cid, err := node.ClusterID()
	if err != nil {
		return err
	}
	c.nodeInfo.ClusterID = cid

	// Leader
	c.nodeInfo.Leader = "leader.mesos:5050"

	return nil
}

// newConfig establishes our default, base configuration.
func newConfig() Config {
	return Config{
		Collector: CollectorConfig{
			HTTPProfiler: false,
			Framework: &framework.Collector{
				ListenEndpointFlag:         "127.0.0.1:8124",
				RecordInputLogFlag:         false,
				InputLimitAmountKBytesFlag: 20480,
				InputLimitPeriodFlag:       60,
			},
			MesosAgent: &mesosAgent.Collector{
				PollPeriod:      time.Duration(60 * time.Second),
				Port:            5051,
				RequestProtocol: "http",
			},
			Node: &node.Collector{
				PollPeriod: time.Duration(60 * time.Second),
			},
		},
		Producers: ProducersConfig{
			HTTPProducerConfig: httpProducer.Config{
				CacheExpiry: time.Duration(120 * time.Second),
				Port:        9000,
			},
		},
		LogLevel: "info",
	}
}

// getNewConfig loads the configuration and sets precedence of configuration values.
// For example: command line flags override values provided in the config file.
func getNewConfig(args []string) (Config, error) {
	c := newConfig()
	thisFlagSet := flag.NewFlagSet("", flag.ExitOnError)
	c.setFlags(thisFlagSet)

	// Override default config with CLI flags if any
	if err := thisFlagSet.Parse(args); err != nil {
		fmt.Println("Errors encountered parsing flags.")
		return c, err
	}

	// If the -version flag was passed, ignore all other args, print the version, and exit
	if c.VersionFlag {
		fmt.Printf(strings.Join([]string{
			fmt.Sprintf("DC/OS Metrics Service (%s)", c.DCOSRole),
			fmt.Sprintf("Version: %s", VERSION),
			fmt.Sprintf("Revision: %s", REVISION),
			fmt.Sprintf("HTTP User-Agent: %s", httpClient.USERAGENT),
		}, "\n"))
		os.Exit(0)
	}

	if len(c.ConfigPath) > 0 {
		if err := c.loadConfig(); err != nil {
			return c, err
		}
	} else {
		log.Warnf("No config file specified, using all defaults.")
	}

	if len(strings.Split(c.DCOSRole, " ")) != 1 {
		return c, fmt.Errorf("error: must specify exactly one DC/OS role (master or agent)")
	}

	if c.DCOSRole != dcos.RoleMaster && c.DCOSRole != dcos.RoleAgent {
		return c, fmt.Errorf("error: expected role to be 'master' or 'agent, got: %s", c.DCOSRole)
	}

	// Ensure that data is collected from the Mesos Agent more
	// regularly than it is evicted from the cache, to avoid
	// missing data for long-running tasks
	minCacheExpiry := c.Collector.MesosAgent.PollPeriod * 2
	if c.Producers.HTTPProducerConfig.CacheExpiry < minCacheExpiry {
		log.Warnf("Configured HTTPProducer.CacheExpiry value was too low. It has been overridden to %v", minCacheExpiry)
		c.Producers.HTTPProducerConfig.CacheExpiry = minCacheExpiry
	}

	// Note: .getNodeInfo() is last so we are sure we have all the
	// configuration we need from flags and config file to make
	// this run correctly.
	if err := c.getNodeInfo(); err != nil {
		return c, err
	}

	// Set the client for the collector to reuse in GET operations
	// to local state and other HTTP sessions
	collectorClient, err := httpHelpers.NewMetricsClient(c.CACertificatePath, c.IAMConfigPath)
	if err != nil {
		return c, err
	}

	c.Collector.MesosAgent.HTTPClient = collectorClient
	return c, nil
}
<commit_msg>Fall back to HTTP on mesos state fetch error (#113)<commit_after>// Copyright 2016 Mesosphere, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/dcos/dcos-go/dcos"
	"github.com/dcos/dcos-go/dcos/nodeutil"
	"github.com/dcos/dcos-metrics/collectors"
	"github.com/dcos/dcos-metrics/collectors/framework"
	mesosAgent "github.com/dcos/dcos-metrics/collectors/mesos/agent"
	"github.com/dcos/dcos-metrics/collectors/node"
	httpProducer "github.com/dcos/dcos-metrics/producers/http"
	httpClient "github.com/dcos/dcos-metrics/util/http/client"
	httpHelpers "github.com/dcos/dcos-metrics/util/http/helpers"

	log "github.com/Sirupsen/logrus"
	yaml "gopkg.in/yaml.v2"
)

var (
	// VERSION set by $(git describe --always)
	// Set by scripts/build.sh, executed by `make build`
	VERSION = "unset"
	// REVISION set by $(git rev-parse --shore HEAD)
	// Set by scripts/build.sh, executed by `make build`
	REVISION = "unset"
)

// Config defines the top-level configuration options for the dcos-metrics-collector project.
// It is (currently) broken up into two main sections: collectors and producers.
type Config struct {
	// Config from the service config file
	Collector         CollectorConfig `yaml:"collector"`
	Producers         ProducersConfig `yaml:"producers"`
	IAMConfigPath     string          `yaml:"iam_config_path"`
	CACertificatePath string          `yaml:"ca_certificate_path"`

	// Node info
	nodeInfo collectors.NodeInfo

	// Flag configuration
	DCOSRole    string
	ConfigPath  string
	LogLevel    string
	VersionFlag bool
}

// CollectorConfig contains configuration options relevant to the "collector"
// portion of this project. That is, the code responsible for querying Mesos,
// et. al to gather metrics and send them to a "producer".
type CollectorConfig struct {
	HTTPProfiler bool                  `yaml:"http_profiler"`
	Framework    *framework.Collector  `yaml:"framework,omitempty"`
	Node         *node.Collector       `yaml:"node,omitempty"`
	MesosAgent   *mesosAgent.Collector `yaml:"mesos_agent,omitempty"`
}

// ProducersConfig contains references to other structs that provide individual producer configs.
// The configuration for all producers is then located in their corresponding packages.
//
// For example: Config.Producers.KafkaProducerConfig references kafkaProducer.Config. This struct
// contains an optional Kafka configuration. This configuration is available in the source file
// 'producers/kafka/kafka.go'. It is then the responsibility of the individual producers to
// validate the configuration the user has provided and panic if necessary.
type ProducersConfig struct {
	HTTPProducerConfig httpProducer.Config `yaml:"http,omitempty"`
	//KafkaProducerConfig  kafkaProducer.Config  `yaml:"kafka,omitempty"`
	//StatsdProducerConfig statsdProducer.Config `yaml:"statsd,omitempty"`
}

func (c *Config) setFlags(fs *flag.FlagSet) {
	fs.StringVar(&c.ConfigPath, "config", c.ConfigPath, "The path to the config file.")
	fs.StringVar(&c.LogLevel, "loglevel", c.LogLevel, "Logging level (default: info). Must be one of: debug, info, warn, error, fatal, panic.")
	fs.StringVar(&c.DCOSRole, "role", c.DCOSRole, "The DC/OS role this instance runs on.")
	fs.BoolVar(&c.VersionFlag, "version", c.VersionFlag, "Print version and revsion then exit")
}

func (c *Config) loadConfig() error {
	fileByte, err := ioutil.ReadFile(c.ConfigPath)
	if err != nil {
		return err
	}

	if err = yaml.Unmarshal(fileByte, &c); err != nil {
		return err
	}

	return nil
}

func (c *Config) getNodeInfo(attemptSSL bool) error {
	log.Debug("Getting node info")
	client, err := httpHelpers.NewMetricsClient(c.CACertificatePath, c.IAMConfigPath)
	if err != nil {
		return err
	}

	// If there is no available certificate, immediately drop back to HTTP
	useSSL := attemptSSL && len(c.IAMConfigPath) > 0
	stateURL := url.URL{
		Scheme: "http",
		Host:   "leader.mesos:5050",
		Path:   "/state",
	}
	if useSSL {
		stateURL.Scheme = "https"
	}

	// Create a new DC/OS nodeutil instance
	node, err := nodeutil.NewNodeInfo(client, c.DCOSRole, nodeutil.OptionMesosStateURL(stateURL.String()))
	if err != nil {
		return fmt.Errorf("error: could not get nodeInfo: %s", err)
	}

	// Get node IP address
	ip, err := node.DetectIP()
	if err != nil {
		return fmt.Errorf("error: could not detect node IP: %s", err)
	}
	c.nodeInfo.IPAddress = ip.String()
	c.nodeInfo.Hostname = c.nodeInfo.IPAddress // TODO(roger): need hostname support in nodeutil

	// Get Mesos master/agent ID
	mid, err := node.MesosID(nil)
	if err != nil {
		// It's possible that we encountered an SSL error
		if useSSL {
			log.Warnf("Received an error when attempting to get Mesos ID: %q; falling back to HTTP", err)
			return c.getNodeInfo(false)
		}
		return fmt.Errorf("error: could not get Mesos node ID: %s", err)
	}
	c.nodeInfo.MesosID = mid

	// Get cluster ID
	cid, err := node.ClusterID()
	if err != nil {
		return err
	}
	c.nodeInfo.ClusterID = cid

	// Leader
	c.nodeInfo.Leader = "leader.mesos:5050"

	return nil
}

// newConfig establishes our default, base configuration.
func newConfig() Config {
	return Config{
		Collector: CollectorConfig{
			HTTPProfiler: false,
			Framework: &framework.Collector{
				ListenEndpointFlag:         "127.0.0.1:8124",
				RecordInputLogFlag:         false,
				InputLimitAmountKBytesFlag: 20480,
				InputLimitPeriodFlag:       60,
			},
			MesosAgent: &mesosAgent.Collector{
				PollPeriod:      time.Duration(60 * time.Second),
				Port:            5051,
				RequestProtocol: "http",
			},
			Node: &node.Collector{
				PollPeriod: time.Duration(60 * time.Second),
			},
		},
		Producers: ProducersConfig{
			HTTPProducerConfig: httpProducer.Config{
				CacheExpiry: time.Duration(120 * time.Second),
				Port:        9000,
			},
		},
		LogLevel: "info",
	}
}

// getNewConfig loads the configuration and sets precedence of configuration values.
// For example: command line flags override values provided in the config file.
func getNewConfig(args []string) (Config, error) {
	c := newConfig()
	thisFlagSet := flag.NewFlagSet("", flag.ExitOnError)
	c.setFlags(thisFlagSet)

	// Override default config with CLI flags if any
	if err := thisFlagSet.Parse(args); err != nil {
		fmt.Println("Errors encountered parsing flags.")
		return c, err
	}

	// If the -version flag was passed, ignore all other args, print the version, and exit
	if c.VersionFlag {
		fmt.Printf(strings.Join([]string{
			fmt.Sprintf("DC/OS Metrics Service (%s)", c.DCOSRole),
			fmt.Sprintf("Version: %s", VERSION),
			fmt.Sprintf("Revision: %s", REVISION),
			fmt.Sprintf("HTTP User-Agent: %s", httpClient.USERAGENT),
		}, "\n"))
		os.Exit(0)
	}

	if len(c.ConfigPath) > 0 {
		if err := c.loadConfig(); err != nil {
			return c, err
		}
	} else {
		log.Warnf("No config file specified, using all defaults.")
	}

	if len(strings.Split(c.DCOSRole, " ")) != 1 {
		return c, fmt.Errorf("error: must specify exactly one DC/OS role (master or agent)")
	}

	if c.DCOSRole != dcos.RoleMaster && c.DCOSRole != dcos.RoleAgent {
		return c, fmt.Errorf("error: expected role to be 'master' or 'agent, got: %s", c.DCOSRole)
	}

	// Ensure that data is collected from the Mesos Agent more
	// regularly than it is evicted from the cache, to avoid
	// missing data for long-running tasks
	minCacheExpiry := c.Collector.MesosAgent.PollPeriod * 2
	if c.Producers.HTTPProducerConfig.CacheExpiry < minCacheExpiry {
		log.Warnf("Configured HTTPProducer.CacheExpiry value was too low. It has been overridden to %v", minCacheExpiry)
		c.Producers.HTTPProducerConfig.CacheExpiry = minCacheExpiry
	}

	// Note: .getNodeInfo() is last so we are sure we have all the
	// configuration we need from flags and config file to make
	// this run correctly.
	if err := c.getNodeInfo(true); err != nil {
		return c, err
	}

	// Set the client for the collector to reuse in GET operations
	// to local state and other HTTP sessions
	collectorClient, err := httpHelpers.NewMetricsClient(c.CACertificatePath, c.IAMConfigPath)
	if err != nil {
		return c, err
	}

	c.Collector.MesosAgent.HTTPClient = collectorClient
	return c, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"code.google.com/p/gcfg"
	"os"
)

type CliConf struct {
	Main struct {
		Server string
		Wallet string
	}
	Entry struct {
		Chainid string
		Extid   string
	}
}

const defaultConf = `
[main]
Server	= localhost:8088
Wallet	= "$HOME/.factom/ecwallet"
[entry]
Chainid	= ""
Extid	= ""
`

func ReadConfig() *CliConf {
	cfg := new(CliConf)
	filename := os.Getenv("HOME") + "/.factom/factom-cli.conf"
	if err := gcfg.ReadFileInto(cfg, filename); err != nil {
		gcfg.ReadStringInto(cfg, defaultConf)
	}
	return cfg
}
<commit_msg>replaced code.google.com/p/gcfg with new upstream<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"gopkg.in/gcfg.v1"
	"os"
)

type CliConf struct {
	Main struct {
		Server string
		Wallet string
	}
	Entry struct {
		Chainid string
		Extid   string
	}
}

const defaultConf = `
[main]
Server	= localhost:8088
Wallet	= "$HOME/.factom/ecwallet"
[entry]
Chainid	= ""
Extid	= ""
`

func ReadConfig() *CliConf {
	cfg := new(CliConf)
	filename := os.Getenv("HOME") + "/.factom/factom-cli.conf"
	if err := gcfg.ReadFileInto(cfg, filename); err != nil {
		gcfg.ReadStringInto(cfg, defaultConf)
	}
	return cfg
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package controller

import (
	"fmt"

	"github.com/go-kit/kit/log/level"
	habv1beta1 "github.com/kinvolk/habitat-operator/pkg/apis/habitat/v1beta1"
	apiv1 "k8s.io/api/core/v1"
	"k8s.io/client-go/tools/cache"
)

func (hc *HabitatController) cachePersistentVolumeClaims() {
	source := newListWatchFromClientWithLabels(
		hc.config.KubernetesClientset.CoreV1().RESTClient(),
		"persistentvolumeclaims",
		apiv1.NamespaceAll,
		labelListOptions())

	hc.cmInformer = cache.NewSharedIndexInformer(
		source,
		&apiv1.PersistentVolumeClaim{},
		resyncPeriod,
		cache.Indexers{},
	)

	hc.cmInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		UpdateFunc: hc.handlePVCUpdate,
		DeleteFunc: hc.handlePVCDelete,
	})

	hc.cmInformerSynced = hc.pvcInformer.HasSynced
}

// findHabForPVC looks for a matching Habitat object for a PVC.
// This method is called when the PVC has been deleted or its status is Lost,
// so finding a matching Habitat means that this object has lost its storage.
func (hc *HabitatController) findHabForPVC(pvc *apiv1.PersistentVolumeClaim) {
	// TODO(asymmetric) Is there a way to find the Habitat without having to produce the key ourselves?
	key := fmt.Sprintf("%s/%s", pvc.Namespace, pvc.Labels[habv1beta1.HabitatNameLabel])

	_, exists, err := hc.habInformer.GetStore().GetByKey(key)
	if err != nil {
		level.Error(hc.logger).Log("msg", "Failed to get key in Store", "obj", key)
		return
	} else if !exists {
		level.Debug(hc.logger).Log("msg", "No matching Habitat found for PVC", "name", pvc.Name)
		return
	} else {
		level.Error(hc.logger).Log("msg", "A PVC has lost its PersistentVolume", "name", pvc.Name)
	}
}

func (hc *HabitatController) handlePVCUpdate(oldObj, newObj interface{}) {
	pvc, ok := newObj.(*apiv1.PersistentVolumeClaim)
	if !ok {
		level.Error(hc.logger).Log("msg", "Failed to type assert PersistentVolumeClaim", "obj", newObj)
		return
	}

	if pvc.Status.Phase == apiv1.ClaimLost {
		hc.findHabForPVC(pvc)
	}
}

func (hc *HabitatController) handlePVCDelete(obj interface{}) {
	pvc, ok := obj.(*apiv1.PersistentVolumeClaim)
	if !ok {
		level.Error(hc.logger).Log("msg", "Failed to type assert PersistentVolumeClaim", "obj", obj)
		return
	}

	hc.findHabForPVC(pvc)
}
<commit_msg>Add TODO<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package controller

import (
	"fmt"

	"github.com/go-kit/kit/log/level"
	habv1beta1 "github.com/kinvolk/habitat-operator/pkg/apis/habitat/v1beta1"
	apiv1 "k8s.io/api/core/v1"
	"k8s.io/client-go/tools/cache"
)

func (hc *HabitatController) cachePersistentVolumeClaims() {
	source := newListWatchFromClientWithLabels(
		hc.config.KubernetesClientset.CoreV1().RESTClient(),
		"persistentvolumeclaims",
		apiv1.NamespaceAll,
		labelListOptions())

	hc.cmInformer = cache.NewSharedIndexInformer(
		source,
		&apiv1.PersistentVolumeClaim{},
		resyncPeriod,
		cache.Indexers{},
	)

	hc.cmInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		UpdateFunc: hc.handlePVCUpdate,
		DeleteFunc: hc.handlePVCDelete,
	})

	hc.cmInformerSynced = hc.pvcInformer.HasSynced
}

// findHabForPVC looks for a matching Habitat object for a PVC.
// This method is called when the PVC has been deleted or its status is Lost,
// so finding a matching Habitat means that this object has lost its storage.
func (hc *HabitatController) findHabForPVC(pvc *apiv1.PersistentVolumeClaim) {
	// TODO(asymmetric) Is there a way to find the Habitat without having to produce the key ourselves?
	key := fmt.Sprintf("%s/%s", pvc.Namespace, pvc.Labels[habv1beta1.HabitatNameLabel])

	_, exists, err := hc.habInformer.GetStore().GetByKey(key)
	if err != nil {
		level.Error(hc.logger).Log("msg", "Failed to get key in Store", "obj", key)
		return
	} else if !exists {
		level.Debug(hc.logger).Log("msg", "No matching Habitat found for PVC", "name", pvc.Name)
		return
	} else {
		// TODO(asymmetric) Should we also check the Habitat's status?
		level.Error(hc.logger).Log("msg", "A PVC has lost its PersistentVolume", "name", pvc.Name)
	}
}

func (hc *HabitatController) handlePVCUpdate(oldObj, newObj interface{}) {
	pvc, ok := newObj.(*apiv1.PersistentVolumeClaim)
	if !ok {
		level.Error(hc.logger).Log("msg", "Failed to type assert PersistentVolumeClaim", "obj", newObj)
		return
	}

	if pvc.Status.Phase == apiv1.ClaimLost {
		hc.findHabForPVC(pvc)
	}
}

func (hc *HabitatController) handlePVCDelete(obj interface{}) {
	pvc, ok := obj.(*apiv1.PersistentVolumeClaim)
	if !ok {
		level.Error(hc.logger).Log("msg", "Failed to type assert PersistentVolumeClaim", "obj", obj)
		return
	}

	hc.findHabForPVC(pvc)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Nuclio Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
	"context"
	"strings"
	"time"

	"github.com/nuclio/nuclio/pkg/common"
	"github.com/nuclio/nuclio/pkg/platform"
	nuclioio "github.com/nuclio/nuclio/pkg/platform/kube/apis/nuclio.io/v1beta1"
	"github.com/nuclio/nuclio/pkg/platform/kube/operator"

	"github.com/nuclio/errors"
	"github.com/nuclio/logger"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/validation"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/tools/cache"
)

type apiGatewayOperator struct {
	logger     logger.Logger
	controller *Controller
	operator   operator.Operator
}

func newAPIGatewayOperator(parentLogger logger.Logger,
	controller *Controller,
	resyncInterval *time.Duration,
	numWorkers int) (*apiGatewayOperator, error) {
	var err error

	loggerInstance := parentLogger.GetChild("apigateway")

	newAPIGatewayOperator := &apiGatewayOperator{
		logger:     loggerInstance,
		controller: controller,
	}

	// create an api gateway operator
	newAPIGatewayOperator.operator, err = operator.NewMultiWorker(loggerInstance,
		numWorkers,
		newAPIGatewayOperator.getListWatcher(controller.namespace),
		&nuclioio.NuclioAPIGateway{},
		resyncInterval,
		newAPIGatewayOperator)

	if err != nil {
		return nil, errors.Wrap(err, "Failed to create api gateway operator")
	}

	parentLogger.DebugWith("Created api gateway operator",
		"numWorkers", numWorkers,
		"resyncInterval", resyncInterval)

	return newAPIGatewayOperator, nil
}

// CreateOrUpdate handles creation/update of an object
func (ago *apiGatewayOperator) CreateOrUpdate(ctx context.Context, object runtime.Object) error {
	var err error

	apiGateway, objectIsAPIGateway := object.(*nuclioio.NuclioAPIGateway)
	if !objectIsAPIGateway {
		return errors.New("Received unexpected object, expected api gateway")
	}

	// validate the state is inside states to respond to
	if !ago.shouldRespondToState(apiGateway.Status.State) {
		ago.logger.DebugWith("Api gateway state is not waiting for creation/update, skipping create/update",
			"name", apiGateway.Spec.Name,
			"state", apiGateway.Status.State)
		return nil
	}

	apiGateway.Status.Description = apiGateway.Spec.Description

	// set default project-name if none given
	if apiGateway.Labels["nuclio.io/project-name"] == "" {
		apiGateway.Labels["nuclio.io/project-name"] = "default"
	}

	// validate api gateway name is according to k8s convention
	errorMessages := validation.IsQualifiedName(apiGateway.Name)
	if len(errorMessages) != 0 {
		joinedErrorMessage := strings.Join(errorMessages, ", ")
		return errors.Errorf("Api gateway name doesn't conform to k8s naming convention. Errors: %s", joinedErrorMessage)
	}

	// create/update the api gateway
	if _, err = ago.controller.apigatewayresClient.CreateOrUpdate(ctx, apiGateway); err != nil {
		ago.logger.WarnWith("Failed to create/update api gateway. Updating state accordingly")
		if err := ago.setAPIGatewayState(apiGateway, platform.APIGatewayStateError, err); err != nil {
			ago.logger.WarnWith("Failed to set api gateway state as error", "err", err)
		}

		return errors.Wrap(err, "Failed to create/update api gateway")
	}

	// wait for api gateway to become available
	ago.controller.apigatewayresClient.WaitAvailable(ctx, apiGateway.Namespace, apiGateway.Name)

	// set state to ready
	if err := ago.setAPIGatewayState(apiGateway, platform.APIGatewayStateReady, nil); err != nil {
		return errors.Wrap(err, "Failed to set api gateway state after it was successfully created")
	}

	ago.logger.DebugWith("Successfully created/updated api gateway", "apiGateway", apiGateway)

	return nil
}

// Delete handles delete of an object
func (ago *apiGatewayOperator) Delete(ctx context.Context, namespace string, name string) error {
	ago.controller.apigatewayresClient.Delete(ctx, namespace, name)

	return nil
}

func (ago *apiGatewayOperator) getListWatcher(namespace string) cache.ListerWatcher {
	return &cache.ListWatch{
		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
			return ago.controller.nuclioClientSet.NuclioV1beta1().NuclioAPIGateways(namespace).List(options)
		},
		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
			return ago.controller.nuclioClientSet.NuclioV1beta1().NuclioAPIGateways(namespace).Watch(options)
		},
	}
}

func (ago *apiGatewayOperator) shouldRespondToState(state platform.APIGatewayState) bool {
	statesToRespond := []string{
		string(platform.APIGatewayStateWaitingForProvisioning),
		string(platform.APIGatewayStateNone),
	}

	return common.StringSliceContainsString(statesToRespond, string(state))
}

func (ago *apiGatewayOperator) setAPIGatewayState(apiGateway *nuclioio.NuclioAPIGateway,
	state platform.APIGatewayState,
	lastError error) error {
	ago.logger.DebugWith("Setting api gateway state", "name", apiGateway.Name, "state", state)

	apiGateway.Status.State = state

	// if a last error was passed, set it
	if lastError != nil {
		apiGateway.Status.LastError = lastError.Error()
	}

	// try to update the api gateway with the new state
	_, err := ago.controller.nuclioClientSet.NuclioV1beta1().NuclioAPIGateways(apiGateway.Namespace).Update(apiGateway)
	return err
}

func (ago *apiGatewayOperator) start() error {
	go ago.operator.Start() // nolint: errcheck

	return nil
}
<commit_msg>[Fix] Creating api-gateway without labels panics (#1882)<commit_after>/*
Copyright 2017 The Nuclio Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
	"context"
	"strings"
	"time"

	"github.com/nuclio/nuclio/pkg/common"
	"github.com/nuclio/nuclio/pkg/platform"
	nuclioio "github.com/nuclio/nuclio/pkg/platform/kube/apis/nuclio.io/v1beta1"
	"github.com/nuclio/nuclio/pkg/platform/kube/operator"

	"github.com/nuclio/errors"
	"github.com/nuclio/logger"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/validation"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/tools/cache"
)

type apiGatewayOperator struct {
	logger     logger.Logger
	controller *Controller
	operator   operator.Operator
}

func newAPIGatewayOperator(parentLogger logger.Logger,
	controller *Controller,
	resyncInterval *time.Duration,
	numWorkers int) (*apiGatewayOperator, error) {
	var err error

	loggerInstance := parentLogger.GetChild("apigateway")

	newAPIGatewayOperator := &apiGatewayOperator{
		logger:     loggerInstance,
		controller: controller,
	}

	// create an api gateway operator
	newAPIGatewayOperator.operator, err = operator.NewMultiWorker(loggerInstance,
		numWorkers,
		newAPIGatewayOperator.getListWatcher(controller.namespace),
		&nuclioio.NuclioAPIGateway{},
		resyncInterval,
		newAPIGatewayOperator)

	if err != nil {
		return nil, errors.Wrap(err, "Failed to create api gateway operator")
	}

	parentLogger.DebugWith("Created api gateway operator",
		"numWorkers", numWorkers,
		"resyncInterval", resyncInterval)

	return newAPIGatewayOperator, nil
}

// CreateOrUpdate handles creation/update of an object
func (ago *apiGatewayOperator) CreateOrUpdate(ctx context.Context, object runtime.Object) error {
	var err error

	apiGateway, objectIsAPIGateway := object.(*nuclioio.NuclioAPIGateway)
	if !objectIsAPIGateway {
		return errors.New("Received unexpected object, expected api gateway")
	}

	// validate the state is inside states to respond to
	if !ago.shouldRespondToState(apiGateway.Status.State) {
		ago.logger.DebugWith("Api gateway state is not waiting for creation/update, skipping create/update",
			"name", apiGateway.Spec.Name,
			"state", apiGateway.Status.State)
		return nil
	}

	apiGateway.Status.Description = apiGateway.Spec.Description

	if apiGateway.Labels == nil {
		apiGateway.Labels = map[string]string{}
	}

	// set default project-name if none given
	if apiGateway.Labels["nuclio.io/project-name"] == "" {
		apiGateway.Labels["nuclio.io/project-name"] = "default"
	}

	// validate api gateway name is according to k8s convention
	errorMessages := validation.IsQualifiedName(apiGateway.Name)
	if len(errorMessages) != 0 {
		joinedErrorMessage := strings.Join(errorMessages, ", ")
		return errors.Errorf("Api gateway name doesn't conform to k8s naming convention. Errors: %s", joinedErrorMessage)
	}

	// create/update the api gateway
	if _, err = ago.controller.apigatewayresClient.CreateOrUpdate(ctx, apiGateway); err != nil {
		ago.logger.WarnWith("Failed to create/update api gateway. Updating state accordingly")
		if err := ago.setAPIGatewayState(apiGateway, platform.APIGatewayStateError, err); err != nil {
			ago.logger.WarnWith("Failed to set api gateway state as error", "err", err)
		}

		return errors.Wrap(err, "Failed to create/update api gateway")
	}

	// wait for api gateway to become available
	ago.controller.apigatewayresClient.WaitAvailable(ctx, apiGateway.Namespace, apiGateway.Name)

	// set state to ready
	if err := ago.setAPIGatewayState(apiGateway, platform.APIGatewayStateReady, nil); err != nil {
		return errors.Wrap(err, "Failed to set api gateway state after it was successfully created")
	}

	ago.logger.DebugWith("Successfully created/updated api gateway", "apiGateway", apiGateway)

	return nil
}

// Delete handles delete of an object
func (ago *apiGatewayOperator) Delete(ctx context.Context, namespace string, name string) error {
	ago.controller.apigatewayresClient.Delete(ctx, namespace, name)

	return nil
}

func (ago *apiGatewayOperator) getListWatcher(namespace string) cache.ListerWatcher {
	return &cache.ListWatch{
		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
			return ago.controller.nuclioClientSet.NuclioV1beta1().NuclioAPIGateways(namespace).List(options)
		},
		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
			return ago.controller.nuclioClientSet.NuclioV1beta1().NuclioAPIGateways(namespace).Watch(options)
		},
	}
}

func (ago *apiGatewayOperator) shouldRespondToState(state platform.APIGatewayState) bool {
	statesToRespond := []string{
		string(platform.APIGatewayStateWaitingForProvisioning),
		string(platform.APIGatewayStateNone),
	}

	return common.StringSliceContainsString(statesToRespond, string(state))
}

func (ago *apiGatewayOperator) setAPIGatewayState(apiGateway *nuclioio.NuclioAPIGateway,
	state platform.APIGatewayState,
	lastError error) error {
	ago.logger.DebugWith("Setting api gateway state", "name", apiGateway.Name, "state", state)

	apiGateway.Status.State = state

	// if a last error was passed, set it
	if lastError != nil {
		apiGateway.Status.LastError = lastError.Error()
	}

	// try to update the api gateway with the new state
	_, err := ago.controller.nuclioClientSet.NuclioV1beta1().NuclioAPIGateways(apiGateway.Namespace).Update(apiGateway)
	return err
}

func (ago *apiGatewayOperator) start() error {
	go ago.operator.Start() // nolint: errcheck

	return nil
}
<|endoftext|>


<commit_before>package baremetal

import (
	"context"
	"fmt"
	"reflect"

	"github.com/scaleway/scaleway-cli/internal/core"
	baremetal "github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
	"github.com/scaleway/scaleway-sdk-go/scw"
)

func serverCreateBuilder(c *core.Command) *core.Command {
	type baremetalCreateServerRequestCustom struct {
		Zone scw.Zone `json:"-"`
		// OrganizationID with which the server will be created
		OrganizationID *string `json:"organization_id"`
		// ProjectID with which the server will be created
		ProjectID *string `json:"project_id"`
		// Name of the server (≠hostname)
		Name string `json:"name"`
		// Description associated to the server, max 255 characters
		Description string `json:"description"`
		// Tags associated with the server
		Tags []string `json:"tags"`
		// Type of the server
		Type string
	}

	c.ArgsType = reflect.TypeOf(baremetalCreateServerRequestCustom{})

	c.ArgSpecs.DeleteByName("offer-id")

	c.ArgSpecs.GetByName("name").Default = core.RandomValueGenerator("bm")
	c.ArgSpecs.GetByName("description").Required = false

	c.ArgSpecs.AddBefore("tags.{index}", &core.ArgSpec{
		Name:  "type",
		Short: "Server commercial type",
	})

	c.Run = func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
		client := core.ExtractClient(ctx)
		api := baremetal.NewAPI(client)

		tmpRequest := argsI.(*baremetalCreateServerRequestCustom)
		request := &baremetal.CreateServerRequest{
			Zone:           tmpRequest.Zone,
			OrganizationID: tmpRequest.OrganizationID,
			ProjectID:      tmpRequest.ProjectID,
			Name:           tmpRequest.Name,
			Description:    tmpRequest.Description,
			Tags:           tmpRequest.Tags,
		}

		// We need to find the offer ID.
		// While baremetal does not have list offer name filter we are forced to iterate
		// on the list of offers provided.
		offer, err := api.GetOfferByName(&baremetal.GetOfferByNameRequest{
			OfferName: tmpRequest.Type,
			Zone:      tmpRequest.Zone,
		})
		if err != nil {
			return nil, err
		}
		if offer == nil {
			return nil, fmt.Errorf("could not match an offer with the type: %s", tmpRequest.Type)
		}
		request.OfferID = offer.ID

		return api.CreateServer(request)
	}

	c.SeeAlsos = []*core.SeeAlso{
		{
			Short:   "List os",
			Command: "scw baremetal os list",
		},
		{
			Short:   "Install an OS on your server",
			Command: "scw baremetal server install",
		},
	}

	c.Examples = []*core.Example{
		{
			Short:    "Create instance",
			ArgsJSON: `{}`,
		},
		{
			Short:    "Create a GP-BM1-M instance, give it a name and add tags",
			ArgsJSON: `{"type":"GP-BM1-M","name":"foo","tags":["prod","blue"]}`,
		},
	}

	c.WaitFunc = func(ctx context.Context, argsI, respI interface{}) (interface{}, error) {
		api := baremetal.NewAPI(core.ExtractClient(ctx))
		return api.WaitForServer(&baremetal.WaitForServerRequest{
			Zone:          argsI.(*baremetalCreateServerRequestCustom).Zone,
			ServerID:      respI.(*baremetal.Server).ID,
			Timeout:       scw.TimeDurationPtr(serverActionTimeout),
			RetryInterval: core.DefaultRetryInterval,
		})
	}

	return c
}
<commit_msg>feat(baremetal): add support for install in the create command (#2331)<commit_after>package baremetal

import (
	"context"
	"fmt"
	"reflect"

	"github.com/scaleway/scaleway-cli/internal/core"
	baremetal "github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
	"github.com/scaleway/scaleway-sdk-go/scw"
)

func serverCreateBuilder(c *core.Command) *core.Command {
	type baremetalCreateServerRequestCustom struct {
		Zone scw.Zone `json:"-"`
		// OrganizationID with which the server will be created
		OrganizationID *string `json:"organization_id"`
		// ProjectID with which the server will be created
		ProjectID *string `json:"project_id"`
		// Name of the server (≠hostname)
		Name string `json:"name"`
		// Description associated to the server, max 255 characters
		Description string `json:"description"`
		// Tags associated with the server
		Tags []string `json:"tags"`
		// Type of the server
		Type string
		// Installation configuration
		Install *baremetal.CreateServerRequestInstall
	}

	c.ArgsType = reflect.TypeOf(baremetalCreateServerRequestCustom{})

	c.ArgSpecs.DeleteByName("offer-id")

	c.ArgSpecs.GetByName("name").Default = core.RandomValueGenerator("bm")
	c.ArgSpecs.GetByName("description").Required = false

	c.ArgSpecs.AddBefore("tags.{index}", &core.ArgSpec{
		Name:  "type",
		Short: "Server commercial type",
	})

	c.Run = func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
		client := core.ExtractClient(ctx)
		api := baremetal.NewAPI(client)

		tmpRequest := argsI.(*baremetalCreateServerRequestCustom)
		request := &baremetal.CreateServerRequest{
			Zone:           tmpRequest.Zone,
			OrganizationID: tmpRequest.OrganizationID,
			ProjectID:      tmpRequest.ProjectID,
			Name:           tmpRequest.Name,
			Description:    tmpRequest.Description,
			Tags:           tmpRequest.Tags,
		}

		if tmpRequest.Install != nil {
			request.Install = tmpRequest.Install
		}

		// We need to find the offer ID.
		// While baremetal does not have list offer name filter we are forced to iterate
		// on the list of offers provided.
		offer, err := api.GetOfferByName(&baremetal.GetOfferByNameRequest{
			OfferName: tmpRequest.Type,
			Zone:      tmpRequest.Zone,
		})
		if err != nil {
			return nil, err
		}
		if offer == nil {
			return nil, fmt.Errorf("could not match an offer with the type: %s", tmpRequest.Type)
		}
		request.OfferID = offer.ID

		return api.CreateServer(request)
	}

	c.SeeAlsos = []*core.SeeAlso{
		{
			Short:   "List os",
			Command: "scw baremetal os list",
		},
		{
			Short:   "Install an OS on your server",
			Command: "scw baremetal server install",
		},
	}

	c.Examples = []*core.Example{
		{
			Short:    "Create instance",
			ArgsJSON: `{}`,
		},
		{
			Short:    "Create a GP-BM1-M instance, give it a name and add tags",
			ArgsJSON: `{"type":"GP-BM1-M","name":"foo","tags":["prod","blue"]}`,
		},
	}

	c.WaitFunc = func(ctx context.Context, argsI, respI interface{}) (interface{}, error) {
		api := baremetal.NewAPI(core.ExtractClient(ctx))
		return api.WaitForServer(&baremetal.WaitForServerRequest{
			Zone:          argsI.(*baremetalCreateServerRequestCustom).Zone,
			ServerID:      respI.(*baremetal.Server).ID,
			Timeout:       scw.TimeDurationPtr(serverActionTimeout),
			RetryInterval: core.DefaultRetryInterval,
		})
	}

	return c
}
<|endoftext|>