<commit_before>package azure

// Copyright 2017 Microsoft Corporation
//
//  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.

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

const (
	// EnvironmentFilepathName captures the name of the environment variable containing the path to the file
	// to be used while populating the Azure Environment.
	EnvironmentFilepathName = "AZURE_ENVIRONMENT_FILEPATH"

	// NotAvailable is used for endpoints and resource IDs that are not available for a given cloud.
	NotAvailable = "N/A"
)

var environments = map[string]Environment{
	"AZURECHINACLOUD":        ChinaCloud,
	"AZUREGERMANCLOUD":       GermanCloud,
	"AZUREPUBLICCLOUD":       PublicCloud,
	"AZUREUSGOVERNMENTCLOUD": USGovernmentCloud,
}

// ResourceIdentifier contains a set of Azure resource IDs.
type ResourceIdentifier struct {
	Graph               string `json:"graph"`
	KeyVault            string `json:"keyVault"`
	Datalake            string `json:"datalake"`
	Batch               string `json:"batch"`
	OperationalInsights string `json:"operationalInsights"`
	Storage             string `json:"storage"`
	Synapse             string `json:"synapse"`
}

// Environment represents a set of endpoints for each of Azure's Clouds.
type Environment struct {
	Name                         string             `json:"name"`
	ManagementPortalURL          string             `json:"managementPortalURL"`
	PublishSettingsURL           string             `json:"publishSettingsURL"`
	ServiceManagementEndpoint    string             `json:"serviceManagementEndpoint"`
	ResourceManagerEndpoint      string             `json:"resourceManagerEndpoint"`
	ActiveDirectoryEndpoint      string             `json:"activeDirectoryEndpoint"`
	GalleryEndpoint              string             `json:"galleryEndpoint"`
	KeyVaultEndpoint             string             `json:"keyVaultEndpoint"`
	GraphEndpoint                string             `json:"graphEndpoint"`
	ServiceBusEndpoint           string             `json:"serviceBusEndpoint"`
	BatchManagementEndpoint      string             `json:"batchManagementEndpoint"`
	StorageEndpointSuffix        string             `json:"storageEndpointSuffix"`
	SQLDatabaseDNSSuffix         string             `json:"sqlDatabaseDNSSuffix"`
	TrafficManagerDNSSuffix      string             `json:"trafficManagerDNSSuffix"`
	KeyVaultDNSSuffix            string             `json:"keyVaultDNSSuffix"`
	ServiceBusEndpointSuffix     string             `json:"serviceBusEndpointSuffix"`
	ServiceManagementVMDNSSuffix string             `json:"serviceManagementVMDNSSuffix"`
	ResourceManagerVMDNSSuffix   string             `json:"resourceManagerVMDNSSuffix"`
	ContainerRegistryDNSSuffix   string             `json:"containerRegistryDNSSuffix"`
	CosmosDBDNSSuffix            string             `json:"cosmosDBDNSSuffix"`
	TokenAudience                string             `json:"tokenAudience"`
	APIManagementHostNameSuffix  string             `json:"apiManagementHostNameSuffix"`
	SynapseEndpointSuffix        string             `json:"synapseEndpointSuffix"`
	ResourceIdentifiers          ResourceIdentifier `json:"resourceIdentifiers"`
}

var (
	// PublicCloud is the default public Azure cloud environment
	PublicCloud = Environment{
		Name:                         "AzurePublicCloud",
		ManagementPortalURL:          "https://manage.windowsazure.com/",
		PublishSettingsURL:           "https://manage.windowsazure.com/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.windows.net/",
		ResourceManagerEndpoint:      "https://management.azure.com/",
		ActiveDirectoryEndpoint:      "https://login.microsoftonline.com/",
		GalleryEndpoint:              "https://gallery.azure.com/",
		KeyVaultEndpoint:             "https://vault.azure.net/",
		GraphEndpoint:                "https://graph.windows.net/",
		ServiceBusEndpoint:           "https://servicebus.windows.net/",
		BatchManagementEndpoint:      "https://batch.core.windows.net/",
		StorageEndpointSuffix:        "core.windows.net",
		SQLDatabaseDNSSuffix:         "database.windows.net",
		TrafficManagerDNSSuffix:      "trafficmanager.net",
		KeyVaultDNSSuffix:            "vault.azure.net",
		ServiceBusEndpointSuffix:     "servicebus.windows.net",
		ServiceManagementVMDNSSuffix: "cloudapp.net",
		ResourceManagerVMDNSSuffix:   "cloudapp.azure.com",
		ContainerRegistryDNSSuffix:   "azurecr.io",
		CosmosDBDNSSuffix:            "documents.azure.com",
		TokenAudience:                "https://management.azure.com/",
		APIManagementHostNameSuffix:  "azure-api.net",
		SynapseEndpointSuffix:        "dev.azuresynapse.net",
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.windows.net/",
			KeyVault:            "https://vault.azure.net",
			Datalake:            "https://datalake.azure.net/",
			Batch:               "https://batch.core.windows.net/",
			OperationalInsights: "https://api.loganalytics.io",
			Storage:             "https://storage.azure.com/",
			Synapse:             "https://dev.azuresynapse.net",
		},
	}

	// USGovernmentCloud is the cloud environment for the US Government
	USGovernmentCloud = Environment{
		Name:                         "AzureUSGovernmentCloud",
		ManagementPortalURL:          "https://manage.windowsazure.us/",
		PublishSettingsURL:           "https://manage.windowsazure.us/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.usgovcloudapi.net/",
		ResourceManagerEndpoint:      "https://management.usgovcloudapi.net/",
		ActiveDirectoryEndpoint:      "https://login.microsoftonline.us/",
		GalleryEndpoint:              "https://gallery.usgovcloudapi.net/",
		KeyVaultEndpoint:             "https://vault.usgovcloudapi.net/",
		GraphEndpoint:                "https://graph.windows.net/",
		ServiceBusEndpoint:           "https://servicebus.usgovcloudapi.net/",
		BatchManagementEndpoint:      "https://batch.core.usgovcloudapi.net/",
		StorageEndpointSuffix:        "core.usgovcloudapi.net",
		SQLDatabaseDNSSuffix:         "database.usgovcloudapi.net",
		TrafficManagerDNSSuffix:      "usgovtrafficmanager.net",
		KeyVaultDNSSuffix:            "vault.usgovcloudapi.net",
		ServiceBusEndpointSuffix:     "servicebus.usgovcloudapi.net",
		ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
		ResourceManagerVMDNSSuffix:   "cloudapp.usgovcloudapi.net",
		ContainerRegistryDNSSuffix:   "azurecr.us",
		CosmosDBDNSSuffix:            "documents.azure.us",
		TokenAudience:                "https://management.usgovcloudapi.net/",
		APIManagementHostNameSuffix:  "azure-api.us",
		SynapseEndpointSuffix:        NotAvailable,
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.windows.net/",
			KeyVault:            "https://vault.usgovcloudapi.net",
			Datalake:            NotAvailable,
			Batch:               "https://batch.core.usgovcloudapi.net/",
			OperationalInsights: "https://api.loganalytics.us",
			Storage:             "https://storage.azure.com/",
			Synapse:             NotAvailable,
		},
	}

	// ChinaCloud is the cloud environment operated in China
	ChinaCloud = Environment{
		Name:                         "AzureChinaCloud",
		ManagementPortalURL:          "https://manage.chinacloudapi.com/",
		PublishSettingsURL:           "https://manage.chinacloudapi.com/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.chinacloudapi.cn/",
		ResourceManagerEndpoint:      "https://management.chinacloudapi.cn/",
		ActiveDirectoryEndpoint:      "https://login.chinacloudapi.cn/",
		GalleryEndpoint:              "https://gallery.chinacloudapi.cn/",
		KeyVaultEndpoint:             "https://vault.azure.cn/",
		GraphEndpoint:                "https://graph.chinacloudapi.cn/",
		ServiceBusEndpoint:           "https://servicebus.chinacloudapi.cn/",
		BatchManagementEndpoint:      "https://batch.chinacloudapi.cn/",
		StorageEndpointSuffix:        "core.chinacloudapi.cn",
		SQLDatabaseDNSSuffix:         "database.chinacloudapi.cn",
		TrafficManagerDNSSuffix:      "trafficmanager.cn",
		KeyVaultDNSSuffix:            "vault.azure.cn",
		ServiceBusEndpointSuffix:     "servicebus.chinacloudapi.cn",
		ServiceManagementVMDNSSuffix: "chinacloudapp.cn",
		ResourceManagerVMDNSSuffix:   "cloudapp.chinacloudapi.cn",
		ContainerRegistryDNSSuffix:   "azurecr.cn",
		CosmosDBDNSSuffix:            "documents.azure.cn",
		TokenAudience:                "https://management.chinacloudapi.cn/",
		APIManagementHostNameSuffix:  "azure-api.cn",
		SynapseEndpointSuffix:        "dev.azuresynapse.azure.cn",
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.chinacloudapi.cn/",
			KeyVault:            "https://vault.azure.cn",
			Datalake:            NotAvailable,
			Batch:               "https://batch.chinacloudapi.cn/",
			OperationalInsights: NotAvailable,
			Storage:             "https://storage.azure.com/",
			Synapse:             "https://dev.azuresynapse.net",
		},
	}

	// GermanCloud is the cloud environment operated in Germany
	GermanCloud = Environment{
		Name:                         "AzureGermanCloud",
		ManagementPortalURL:          "http://portal.microsoftazure.de/",
		PublishSettingsURL:           "https://manage.microsoftazure.de/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.cloudapi.de/",
		ResourceManagerEndpoint:      "https://management.microsoftazure.de/",
		ActiveDirectoryEndpoint:      "https://login.microsoftonline.de/",
		GalleryEndpoint:              "https://gallery.cloudapi.de/",
		KeyVaultEndpoint:             "https://vault.microsoftazure.de/",
		GraphEndpoint:                "https://graph.cloudapi.de/",
		ServiceBusEndpoint:           "https://servicebus.cloudapi.de/",
		BatchManagementEndpoint:      "https://batch.cloudapi.de/",
		StorageEndpointSuffix:        "core.cloudapi.de",
		SQLDatabaseDNSSuffix:         "database.cloudapi.de",
		TrafficManagerDNSSuffix:      "azuretrafficmanager.de",
		KeyVaultDNSSuffix:            "vault.microsoftazure.de",
		ServiceBusEndpointSuffix:     "servicebus.cloudapi.de",
		ServiceManagementVMDNSSuffix: "azurecloudapp.de",
		ResourceManagerVMDNSSuffix:   "cloudapp.microsoftazure.de",
		ContainerRegistryDNSSuffix:   NotAvailable,
		CosmosDBDNSSuffix:            "documents.microsoftazure.de",
		TokenAudience:                "https://management.microsoftazure.de/",
		APIManagementHostNameSuffix:  NotAvailable,
		SynapseEndpointSuffix:        NotAvailable,
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.cloudapi.de/",
			KeyVault:            "https://vault.microsoftazure.de",
			Datalake:            NotAvailable,
			Batch:               "https://batch.cloudapi.de/",
			OperationalInsights: NotAvailable,
			Storage:             "https://storage.azure.com/",
			Synapse:             NotAvailable,
		},
	}
)

// EnvironmentFromName returns an Environment based on the common name specified.
func EnvironmentFromName(name string) (Environment, error) {
	// IMPORTANT
	// As per @radhikagupta5:
	// This is technical debt, fundamentally here because Kubernetes is not currently accepting
	// contributions to the providers. Once that is an option, the provider should be updated to
	// directly call `EnvironmentFromFile`. Until then, we rely on dispatching Azure Stack environment creation
	// from this method based on the name that is provided to us.
	if strings.EqualFold(name, "AZURESTACKCLOUD") {
		return EnvironmentFromFile(os.Getenv(EnvironmentFilepathName))
	}

	name = strings.ToUpper(name)
	env, ok := environments[name]
	if !ok {
		return env, fmt.Errorf("autorest/azure: There is no cloud environment matching the name %q", name)
	}

	return env, nil
}

// EnvironmentFromFile loads an Environment from a configuration file available on disk.
// This function is particularly useful in the Hybrid Cloud model, where one must define their own
// endpoints.
func EnvironmentFromFile(location string) (unmarshaled Environment, err error) {
	fileContents, err := ioutil.ReadFile(location)
	if err != nil {
		return
	}

	err = json.Unmarshal(fileContents, &unmarshaled)

	return
}

// SetEnvironment updates the environment map with the specified values.
func SetEnvironment(name string, env Environment) {
	environments[strings.ToUpper(name)] = env
}
<commit_msg>add servicebus resourceuri (#566)<commit_after>package azure

// Copyright 2017 Microsoft Corporation
//
//  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.

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

const (
	// EnvironmentFilepathName captures the name of the environment variable containing the path to the file
	// to be used while populating the Azure Environment.
	EnvironmentFilepathName = "AZURE_ENVIRONMENT_FILEPATH"

	// NotAvailable is used for endpoints and resource IDs that are not available for a given cloud.
	NotAvailable = "N/A"
)

var environments = map[string]Environment{
	"AZURECHINACLOUD":        ChinaCloud,
	"AZUREGERMANCLOUD":       GermanCloud,
	"AZUREPUBLICCLOUD":       PublicCloud,
	"AZUREUSGOVERNMENTCLOUD": USGovernmentCloud,
}

// ResourceIdentifier contains a set of Azure resource IDs.
type ResourceIdentifier struct {
	Graph               string `json:"graph"`
	KeyVault            string `json:"keyVault"`
	Datalake            string `json:"datalake"`
	Batch               string `json:"batch"`
	OperationalInsights string `json:"operationalInsights"`
	Storage             string `json:"storage"`
	Synapse             string `json:"synapse"`
	ServiceBus          string `json:"serviceBus"`
}

// Environment represents a set of endpoints for each of Azure's Clouds.
type Environment struct {
	Name                         string             `json:"name"`
	ManagementPortalURL          string             `json:"managementPortalURL"`
	PublishSettingsURL           string             `json:"publishSettingsURL"`
	ServiceManagementEndpoint    string             `json:"serviceManagementEndpoint"`
	ResourceManagerEndpoint      string             `json:"resourceManagerEndpoint"`
	ActiveDirectoryEndpoint      string             `json:"activeDirectoryEndpoint"`
	GalleryEndpoint              string             `json:"galleryEndpoint"`
	KeyVaultEndpoint             string             `json:"keyVaultEndpoint"`
	GraphEndpoint                string             `json:"graphEndpoint"`
	ServiceBusEndpoint           string             `json:"serviceBusEndpoint"`
	BatchManagementEndpoint      string             `json:"batchManagementEndpoint"`
	StorageEndpointSuffix        string             `json:"storageEndpointSuffix"`
	SQLDatabaseDNSSuffix         string             `json:"sqlDatabaseDNSSuffix"`
	TrafficManagerDNSSuffix      string             `json:"trafficManagerDNSSuffix"`
	KeyVaultDNSSuffix            string             `json:"keyVaultDNSSuffix"`
	ServiceBusEndpointSuffix     string             `json:"serviceBusEndpointSuffix"`
	ServiceManagementVMDNSSuffix string             `json:"serviceManagementVMDNSSuffix"`
	ResourceManagerVMDNSSuffix   string             `json:"resourceManagerVMDNSSuffix"`
	ContainerRegistryDNSSuffix   string             `json:"containerRegistryDNSSuffix"`
	CosmosDBDNSSuffix            string             `json:"cosmosDBDNSSuffix"`
	TokenAudience                string             `json:"tokenAudience"`
	APIManagementHostNameSuffix  string             `json:"apiManagementHostNameSuffix"`
	SynapseEndpointSuffix        string             `json:"synapseEndpointSuffix"`
	ResourceIdentifiers          ResourceIdentifier `json:"resourceIdentifiers"`
}

var (
	// PublicCloud is the default public Azure cloud environment
	PublicCloud = Environment{
		Name:                         "AzurePublicCloud",
		ManagementPortalURL:          "https://manage.windowsazure.com/",
		PublishSettingsURL:           "https://manage.windowsazure.com/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.windows.net/",
		ResourceManagerEndpoint:      "https://management.azure.com/",
		ActiveDirectoryEndpoint:      "https://login.microsoftonline.com/",
		GalleryEndpoint:              "https://gallery.azure.com/",
		KeyVaultEndpoint:             "https://vault.azure.net/",
		GraphEndpoint:                "https://graph.windows.net/",
		ServiceBusEndpoint:           "https://servicebus.windows.net/",
		BatchManagementEndpoint:      "https://batch.core.windows.net/",
		StorageEndpointSuffix:        "core.windows.net",
		SQLDatabaseDNSSuffix:         "database.windows.net",
		TrafficManagerDNSSuffix:      "trafficmanager.net",
		KeyVaultDNSSuffix:            "vault.azure.net",
		ServiceBusEndpointSuffix:     "servicebus.windows.net",
		ServiceManagementVMDNSSuffix: "cloudapp.net",
		ResourceManagerVMDNSSuffix:   "cloudapp.azure.com",
		ContainerRegistryDNSSuffix:   "azurecr.io",
		CosmosDBDNSSuffix:            "documents.azure.com",
		TokenAudience:                "https://management.azure.com/",
		APIManagementHostNameSuffix:  "azure-api.net",
		SynapseEndpointSuffix:        "dev.azuresynapse.net",
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.windows.net/",
			KeyVault:            "https://vault.azure.net",
			Datalake:            "https://datalake.azure.net/",
			Batch:               "https://batch.core.windows.net/",
			OperationalInsights: "https://api.loganalytics.io",
			Storage:             "https://storage.azure.com/",
			Synapse:             "https://dev.azuresynapse.net",
			ServiceBus:          "https://servicebus.azure.net/",
		},
	}

	// USGovernmentCloud is the cloud environment for the US Government
	USGovernmentCloud = Environment{
		Name:                         "AzureUSGovernmentCloud",
		ManagementPortalURL:          "https://manage.windowsazure.us/",
		PublishSettingsURL:           "https://manage.windowsazure.us/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.usgovcloudapi.net/",
		ResourceManagerEndpoint:      "https://management.usgovcloudapi.net/",
		ActiveDirectoryEndpoint:      "https://login.microsoftonline.us/",
		GalleryEndpoint:              "https://gallery.usgovcloudapi.net/",
		KeyVaultEndpoint:             "https://vault.usgovcloudapi.net/",
		GraphEndpoint:                "https://graph.windows.net/",
		ServiceBusEndpoint:           "https://servicebus.usgovcloudapi.net/",
		BatchManagementEndpoint:      "https://batch.core.usgovcloudapi.net/",
		StorageEndpointSuffix:        "core.usgovcloudapi.net",
		SQLDatabaseDNSSuffix:         "database.usgovcloudapi.net",
		TrafficManagerDNSSuffix:      "usgovtrafficmanager.net",
		KeyVaultDNSSuffix:            "vault.usgovcloudapi.net",
		ServiceBusEndpointSuffix:     "servicebus.usgovcloudapi.net",
		ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
		ResourceManagerVMDNSSuffix:   "cloudapp.usgovcloudapi.net",
		ContainerRegistryDNSSuffix:   "azurecr.us",
		CosmosDBDNSSuffix:            "documents.azure.us",
		TokenAudience:                "https://management.usgovcloudapi.net/",
		APIManagementHostNameSuffix:  "azure-api.us",
		SynapseEndpointSuffix:        NotAvailable,
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.windows.net/",
			KeyVault:            "https://vault.usgovcloudapi.net",
			Datalake:            NotAvailable,
			Batch:               "https://batch.core.usgovcloudapi.net/",
			OperationalInsights: "https://api.loganalytics.us",
			Storage:             "https://storage.azure.com/",
			Synapse:             NotAvailable,
			ServiceBus:          "https://servicebus.azure.net/",
		},
	}

	// ChinaCloud is the cloud environment operated in China
	ChinaCloud = Environment{
		Name:                         "AzureChinaCloud",
		ManagementPortalURL:          "https://manage.chinacloudapi.com/",
		PublishSettingsURL:           "https://manage.chinacloudapi.com/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.chinacloudapi.cn/",
		ResourceManagerEndpoint:      "https://management.chinacloudapi.cn/",
		ActiveDirectoryEndpoint:      "https://login.chinacloudapi.cn/",
		GalleryEndpoint:              "https://gallery.chinacloudapi.cn/",
		KeyVaultEndpoint:             "https://vault.azure.cn/",
		GraphEndpoint:                "https://graph.chinacloudapi.cn/",
		ServiceBusEndpoint:           "https://servicebus.chinacloudapi.cn/",
		BatchManagementEndpoint:      "https://batch.chinacloudapi.cn/",
		StorageEndpointSuffix:        "core.chinacloudapi.cn",
		SQLDatabaseDNSSuffix:         "database.chinacloudapi.cn",
		TrafficManagerDNSSuffix:      "trafficmanager.cn",
		KeyVaultDNSSuffix:            "vault.azure.cn",
		ServiceBusEndpointSuffix:     "servicebus.chinacloudapi.cn",
		ServiceManagementVMDNSSuffix: "chinacloudapp.cn",
		ResourceManagerVMDNSSuffix:   "cloudapp.chinacloudapi.cn",
		ContainerRegistryDNSSuffix:   "azurecr.cn",
		CosmosDBDNSSuffix:            "documents.azure.cn",
		TokenAudience:                "https://management.chinacloudapi.cn/",
		APIManagementHostNameSuffix:  "azure-api.cn",
		SynapseEndpointSuffix:        "dev.azuresynapse.azure.cn",
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.chinacloudapi.cn/",
			KeyVault:            "https://vault.azure.cn",
			Datalake:            NotAvailable,
			Batch:               "https://batch.chinacloudapi.cn/",
			OperationalInsights: NotAvailable,
			Storage:             "https://storage.azure.com/",
			Synapse:             "https://dev.azuresynapse.net",
			ServiceBus:          "https://servicebus.azure.net/",
		},
	}

	// GermanCloud is the cloud environment operated in Germany
	GermanCloud = Environment{
		Name:                         "AzureGermanCloud",
		ManagementPortalURL:          "http://portal.microsoftazure.de/",
		PublishSettingsURL:           "https://manage.microsoftazure.de/publishsettings/index",
		ServiceManagementEndpoint:    "https://management.core.cloudapi.de/",
		ResourceManagerEndpoint:      "https://management.microsoftazure.de/",
		ActiveDirectoryEndpoint:      "https://login.microsoftonline.de/",
		GalleryEndpoint:              "https://gallery.cloudapi.de/",
		KeyVaultEndpoint:             "https://vault.microsoftazure.de/",
		GraphEndpoint:                "https://graph.cloudapi.de/",
		ServiceBusEndpoint:           "https://servicebus.cloudapi.de/",
		BatchManagementEndpoint:      "https://batch.cloudapi.de/",
		StorageEndpointSuffix:        "core.cloudapi.de",
		SQLDatabaseDNSSuffix:         "database.cloudapi.de",
		TrafficManagerDNSSuffix:      "azuretrafficmanager.de",
		KeyVaultDNSSuffix:            "vault.microsoftazure.de",
		ServiceBusEndpointSuffix:     "servicebus.cloudapi.de",
		ServiceManagementVMDNSSuffix: "azurecloudapp.de",
		ResourceManagerVMDNSSuffix:   "cloudapp.microsoftazure.de",
		ContainerRegistryDNSSuffix:   NotAvailable,
		CosmosDBDNSSuffix:            "documents.microsoftazure.de",
		TokenAudience:                "https://management.microsoftazure.de/",
		APIManagementHostNameSuffix:  NotAvailable,
		SynapseEndpointSuffix:        NotAvailable,
		ResourceIdentifiers: ResourceIdentifier{
			Graph:               "https://graph.cloudapi.de/",
			KeyVault:            "https://vault.microsoftazure.de",
			Datalake:            NotAvailable,
			Batch:               "https://batch.cloudapi.de/",
			OperationalInsights: NotAvailable,
			Storage:             "https://storage.azure.com/",
			Synapse:             NotAvailable,
			ServiceBus:          "https://servicebus.azure.net/",
		},
	}
)

// EnvironmentFromName returns an Environment based on the common name specified.
func EnvironmentFromName(name string) (Environment, error) {
	// IMPORTANT
	// As per @radhikagupta5:
	// This is technical debt, fundamentally here because Kubernetes is not currently accepting
	// contributions to the providers. Once that is an option, the provider should be updated to
	// directly call `EnvironmentFromFile`. Until then, we rely on dispatching Azure Stack environment creation
	// from this method based on the name that is provided to us.
	if strings.EqualFold(name, "AZURESTACKCLOUD") {
		return EnvironmentFromFile(os.Getenv(EnvironmentFilepathName))
	}

	name = strings.ToUpper(name)
	env, ok := environments[name]
	if !ok {
		return env, fmt.Errorf("autorest/azure: There is no cloud environment matching the name %q", name)
	}

	return env, nil
}

// EnvironmentFromFile loads an Environment from a configuration file available on disk.
// This function is particularly useful in the Hybrid Cloud model, where one must define their own
// endpoints.
func EnvironmentFromFile(location string) (unmarshaled Environment, err error) {
	fileContents, err := ioutil.ReadFile(location)
	if err != nil {
		return
	}

	err = json.Unmarshal(fileContents, &unmarshaled)

	return
}

// SetEnvironment updates the environment map with the specified values.
func SetEnvironment(name string, env Environment) {
	environments[strings.ToUpper(name)] = env
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 exec

import (
	"context"
	osexec "os/exec"
	"testing"
	"time"
)

func TestExecutorNoArgs(t *testing.T) {
	ex := New()

	cmd := ex.Command("true")
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %v", err)
	}
	if len(out) != 0 {
		t.Errorf("expected no output, got %q", string(out))
	}

	cmd = ex.Command("false")
	out, err = cmd.CombinedOutput()
	if err == nil {
		t.Errorf("expected failure, got nil error")
	}
	if len(out) != 0 {
		t.Errorf("expected no output, got %q", string(out))
	}
	ee, ok := err.(ExitError)
	if !ok {
		t.Errorf("expected an ExitError, got %+v", err)
	}
	if ee.Exited() {
		if code := ee.ExitStatus(); code != 1 {
			t.Errorf("expected exit status 1, got %d", code)
		}
	}

	cmd = ex.Command("/does/not/exist")
	out, err = cmd.CombinedOutput()
	if err == nil {
		t.Errorf("expected failure, got nil error")
	}
	if ee, ok := err.(ExitError); ok {
		t.Errorf("expected non-ExitError, got %+v", ee)
	}
}

func TestExecutorWithArgs(t *testing.T) {
	ex := New()

	cmd := ex.Command("echo", "stdout")
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %+v", err)
	}
	if string(out) != "stdout\n" {
		t.Errorf("unexpected output: %q", string(out))
	}

	cmd = ex.Command("/bin/sh", "-c", "echo stderr > /dev/stderr")
	out, err = cmd.CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %+v", err)
	}
	if string(out) != "stderr\n" {
		t.Errorf("unexpected output: %q", string(out))
	}
}

func TestLookPath(t *testing.T) {
	ex := New()

	shExpected, _ := osexec.LookPath("sh")
	sh, _ := ex.LookPath("sh")
	if sh != shExpected {
		t.Errorf("unexpected result for LookPath: got %s, expected %s", sh, shExpected)
	}
}

func TestExecutableNotFound(t *testing.T) {
	exec := New()

	cmd := exec.Command("fake_executable_name")
	_, err := cmd.CombinedOutput()
	if err != ErrExecutableNotFound {
		t.Errorf("cmd.CombinedOutput(): Expected error ErrExecutableNotFound but got %v", err)
	}

	cmd = exec.Command("fake_executable_name")
	_, err = cmd.Output()
	if err != ErrExecutableNotFound {
		t.Errorf("cmd.Output(): Expected error ErrExecutableNotFound but got %v", err)
	}

	cmd = exec.Command("fake_executable_name")
	err = cmd.Run()
	if err != ErrExecutableNotFound {
		t.Errorf("cmd.Run(): Expected error ErrExecutableNotFound but got %v", err)
	}
}

func TestStopBeforeStart(t *testing.T) {
	cmd := New().Command("echo", "hello")

	// no panic calling Stop before calling Run
	cmd.Stop()

	cmd.Run()

	// no panic calling Stop after command is done
	cmd.Stop()
}

func TestTimeout(t *testing.T) {
	exec := New()
	ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
	defer cancel()

	err := exec.CommandContext(ctx, "sleep", "2").Run()
	if err != context.DeadlineExceeded {
		t.Errorf("expected %v but got %v", context.DeadlineExceeded, err)
	}
}
<commit_msg>Add test for Cmd.SetEnv<commit_after>/*
Copyright 2017 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 exec

import (
	"context"
	osexec "os/exec"
	"testing"
	"time"
)

func TestExecutorNoArgs(t *testing.T) {
	ex := New()

	cmd := ex.Command("true")
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %v", err)
	}
	if len(out) != 0 {
		t.Errorf("expected no output, got %q", string(out))
	}

	cmd = ex.Command("false")
	out, err = cmd.CombinedOutput()
	if err == nil {
		t.Errorf("expected failure, got nil error")
	}
	if len(out) != 0 {
		t.Errorf("expected no output, got %q", string(out))
	}
	ee, ok := err.(ExitError)
	if !ok {
		t.Errorf("expected an ExitError, got %+v", err)
	}
	if ee.Exited() {
		if code := ee.ExitStatus(); code != 1 {
			t.Errorf("expected exit status 1, got %d", code)
		}
	}

	cmd = ex.Command("/does/not/exist")
	out, err = cmd.CombinedOutput()
	if err == nil {
		t.Errorf("expected failure, got nil error")
	}
	if ee, ok := err.(ExitError); ok {
		t.Errorf("expected non-ExitError, got %+v", ee)
	}
}

func TestExecutorWithArgs(t *testing.T) {
	ex := New()

	cmd := ex.Command("echo", "stdout")
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %+v", err)
	}
	if string(out) != "stdout\n" {
		t.Errorf("unexpected output: %q", string(out))
	}

	cmd = ex.Command("/bin/sh", "-c", "echo stderr > /dev/stderr")
	out, err = cmd.CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %+v", err)
	}
	if string(out) != "stderr\n" {
		t.Errorf("unexpected output: %q", string(out))
	}
}

func TestLookPath(t *testing.T) {
	ex := New()

	shExpected, _ := osexec.LookPath("sh")
	sh, _ := ex.LookPath("sh")
	if sh != shExpected {
		t.Errorf("unexpected result for LookPath: got %s, expected %s", sh, shExpected)
	}
}

func TestExecutableNotFound(t *testing.T) {
	exec := New()

	cmd := exec.Command("fake_executable_name")
	_, err := cmd.CombinedOutput()
	if err != ErrExecutableNotFound {
		t.Errorf("cmd.CombinedOutput(): Expected error ErrExecutableNotFound but got %v", err)
	}

	cmd = exec.Command("fake_executable_name")
	_, err = cmd.Output()
	if err != ErrExecutableNotFound {
		t.Errorf("cmd.Output(): Expected error ErrExecutableNotFound but got %v", err)
	}

	cmd = exec.Command("fake_executable_name")
	err = cmd.Run()
	if err != ErrExecutableNotFound {
		t.Errorf("cmd.Run(): Expected error ErrExecutableNotFound but got %v", err)
	}
}

func TestStopBeforeStart(t *testing.T) {
	cmd := New().Command("echo", "hello")

	// no panic calling Stop before calling Run
	cmd.Stop()

	cmd.Run()

	// no panic calling Stop after command is done
	cmd.Stop()
}

func TestTimeout(t *testing.T) {
	exec := New()
	ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
	defer cancel()

	err := exec.CommandContext(ctx, "sleep", "2").Run()
	if err != context.DeadlineExceeded {
		t.Errorf("expected %v but got %v", context.DeadlineExceeded, err)
	}
}

func TestSetEnv(t *testing.T) {
	ex := New()

	out, err := ex.Command("/bin/sh", "-c", "echo $FOOBAR").CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %+v", err)
	}
	if string(out) != "\n" {
		t.Errorf("unexpected output: %q", string(out))
	}

	cmd := ex.Command("/bin/sh", "-c", "echo $FOOBAR")
	cmd.SetEnv([]string{"FOOBAR=baz"})
	out, err = cmd.CombinedOutput()
	if err != nil {
		t.Errorf("expected success, got %+v", err)
	}
	if string(out) != "baz\n" {
		t.Errorf("unexpected output: %q", string(out))
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package executor

import (
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/ast"
	"github.com/pingcap/tidb/expression"
	"github.com/pingcap/tidb/mysql"
	"github.com/pingcap/tidb/sessionctx"
	"github.com/pingcap/tidb/table"
	"github.com/pingcap/tidb/table/tables"
	"github.com/pingcap/tidb/types"
)

var (
	_ Executor = &UpdateExec{}
	_ Executor = &DeleteExec{}
	_ Executor = &InsertExec{}
	_ Executor = &ReplaceExec{}
	_ Executor = &LoadDataExec{}
)

// updateRecord updates the row specified by the handle `h`, from `oldData` to `newData`.
// `modified` means which columns are really modified. It's used for secondary indices.
// Length of `oldData` and `newData` equals to length of `t.WritableCols()`.
// The return values:
//     1. changed (bool) : does the update really change the row values. e.g. update set i = 1 where i = 1;
//     2. handleChanged (bool) : is the handle changed after the update.
//     3. newHandle (int64) : if handleChanged == true, the newHandle means the new handle after update.
//     4. err (error) : error in the update.
func updateRecord(ctx sessionctx.Context, h int64, oldData, newData []types.Datum, modified []bool, t table.Table,
	onDup bool) (bool, bool, int64, error) {
	var sc = ctx.GetSessionVars().StmtCtx
	var changed, handleChanged = false, false
	// onUpdateSpecified is for "UPDATE SET ts_field = old_value", the
	// timestamp field is explicitly set, but not changed in fact.
	var onUpdateSpecified = make(map[int]bool)
	var newHandle int64

	// We can iterate on public columns not writable columns,
	// because all of them are sorted by their `Offset`, which
	// causes all writable columns are after public columns.
	for i, col := range t.Cols() {
		if modified[i] {
			// Cast changed fields with respective columns.
			v, err := table.CastValue(ctx, newData[i], col.ToInfo())
			if err != nil {
				return false, handleChanged, newHandle, errors.Trace(err)
			}
			newData[i] = v
		}

		if mysql.HasNotNullFlag(col.Flag) && newData[i].IsNull() && sc.BadNullAsWarning {
			var err error
			newData[i], err = table.GetColDefaultValue(ctx, col.ToInfo())
			if err != nil {
				return false, handleChanged, newHandle, errors.Trace(err)
			}
		}
		cmp, err := newData[i].CompareDatum(sc, &oldData[i])
		if err != nil {
			return false, handleChanged, newHandle, errors.Trace(err)
		}
		if cmp != 0 {
			changed = true
			modified[i] = true
			// Rebase auto increment id if the field is changed.
			if mysql.HasAutoIncrementFlag(col.Flag) {
				if newData[i].IsNull() {
					return false, handleChanged, newHandle, table.ErrColumnCantNull.GenByArgs(col.Name)
				}
				val, errTI := newData[i].ToInt64(sc)
				if errTI != nil {
					return false, handleChanged, newHandle, errors.Trace(errTI)
				}
				err := t.RebaseAutoID(ctx, val, true)
				if err != nil {
					return false, handleChanged, newHandle, errors.Trace(err)
				}
			}
			if col.IsPKHandleColumn(t.Meta()) {
				handleChanged = true
				newHandle = newData[i].GetInt64()
			}
		} else {
			if mysql.HasOnUpdateNowFlag(col.Flag) && modified[i] {
				// It's for "UPDATE t SET ts = ts" and ts is a timestamp.
				onUpdateSpecified[i] = true
			}
			modified[i] = false
		}
	}

	// Check the not-null constraints.
	err := table.CheckNotNull(t.Cols(), newData)
	if err != nil {
		return false, handleChanged, newHandle, errors.Trace(err)
	}

	if !changed {
		// See https://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html  CLIENT_FOUND_ROWS
		if ctx.GetSessionVars().ClientCapability&mysql.ClientFoundRows > 0 {
			sc.AddAffectedRows(1)
		}
		return false, handleChanged, newHandle, nil
	}

	// Fill values into on-update-now fields, only if they are really changed.
	for i, col := range t.Cols() {
		if mysql.HasOnUpdateNowFlag(col.Flag) && !modified[i] && !onUpdateSpecified[i] {
			v, errGT := expression.GetTimeValue(ctx, strings.ToUpper(ast.CurrentTimestamp), col.Tp, col.Decimal)
			if errGT != nil {
				return false, handleChanged, newHandle, errors.Trace(errGT)
			}
			newData[i] = v
			modified[i] = true
		}
	}

	if handleChanged {
		skipHandleCheck := false
		if sc.DupKeyAsWarning {
			// if the new handle exists. `UPDATE IGNORE` will avoid removing record, and do nothing.
			err = tables.CheckHandleExists(ctx, t, newHandle, newData)
			if err != nil {
				return false, handleChanged, newHandle, errors.Trace(err)
			}
			skipHandleCheck = true
		}
		err = t.RemoveRecord(ctx, h, oldData)
		if err != nil {
			return false, handleChanged, newHandle, errors.Trace(err)
		}
		newHandle, err = t.AddRecord(ctx, newData, skipHandleCheck)
	} else {
		// Update record to new value and update index.
		err = t.UpdateRecord(ctx, h, oldData, newData, modified)
	}
	if err != nil {
		return false, handleChanged, newHandle, errors.Trace(err)
	}

	if onDup {
		sc.AddAffectedRows(2)
	} else {
		// if handleChanged == true, the `affectedRows` is calculated when add new record.
		if !handleChanged {
			sc.AddAffectedRows(1)
		}
	}
	colSize := make(map[int64]int64)
	for id, col := range t.Cols() {
		val := int64(len(newData[id].GetBytes()) - len(oldData[id].GetBytes()))
		if val != 0 {
			colSize[col.ID] = val
		}
	}
	ctx.GetSessionVars().TxnCtx.UpdateDeltaForTable(t.Meta().ID, 0, 1, colSize)
	return true, handleChanged, newHandle, nil
}

// resetErrDataTooLong reset ErrDataTooLong error msg.
// types.ErrDataTooLong is produced in types.ProduceStrWithSpecifiedTp, there is no column info in there,
// so we reset the error msg here, and wrap old err with errors.Wrap.
func resetErrDataTooLong(colName string, rowIdx int, err error) error {
	newErr := types.ErrDataTooLong.Gen("Data too long for column '%v' at row %v", colName, rowIdx)
	return errors.Wrap(err, newErr)
}

func getTableOffset(schema *expression.Schema, handleCol *expression.Column) int {
	for i, col := range schema.Columns {
		if col.DBName.L == handleCol.DBName.L && col.TblName.L == handleCol.TblName.L {
			return i
		}
	}
	panic("Couldn't get column information when do update/delete")
}
<commit_msg>executer: make updateRecord easier to understand (#7557)<commit_after>// Copyright 2016 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package executor

import (
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/ast"
	"github.com/pingcap/tidb/expression"
	"github.com/pingcap/tidb/mysql"
	"github.com/pingcap/tidb/sessionctx"
	"github.com/pingcap/tidb/table"
	"github.com/pingcap/tidb/table/tables"
	"github.com/pingcap/tidb/types"
)

var (
	_ Executor = &UpdateExec{}
	_ Executor = &DeleteExec{}
	_ Executor = &InsertExec{}
	_ Executor = &ReplaceExec{}
	_ Executor = &LoadDataExec{}
)

// updateRecord updates the row specified by the handle `h`, from `oldData` to `newData`.
// `modified` means which columns are really modified. It's used for secondary indices.
// Length of `oldData` and `newData` equals to length of `t.WritableCols()`.
// The return values:
//     1. changed (bool) : does the update really change the row values. e.g. update set i = 1 where i = 1;
//     2. handleChanged (bool) : is the handle changed after the update.
//     3. newHandle (int64) : if handleChanged == true, the newHandle means the new handle after update.
//     4. err (error) : error in the update.
func updateRecord(ctx sessionctx.Context, h int64, oldData, newData []types.Datum, modified []bool, t table.Table,
	onDup bool) (bool, bool, int64, error) {
	sc := ctx.GetSessionVars().StmtCtx
	changed, handleChanged := false, false
	// onUpdateSpecified is for "UPDATE SET ts_field = old_value", the
	// timestamp field is explicitly set, but not changed in fact.
	onUpdateSpecified := make(map[int]bool)
	var newHandle int64

	// We can iterate on public columns not writable columns,
	// because all of them are sorted by their `Offset`, which
	// causes all writable columns are after public columns.

	// 1. Cast modified values.
	for i, col := range t.Cols() {
		if modified[i] {
			// Cast changed fields with respective columns.
			v, err := table.CastValue(ctx, newData[i], col.ToInfo())
			if err != nil {
				return false, false, 0, errors.Trace(err)
			}
			newData[i] = v
		}
	}

	// 2. Check null.
	for i, col := range t.Cols() {
		if err := col.CheckNotNull(newData[i]); err != nil {
			if sc.BadNullAsWarning {
				newData[i], err = table.GetColDefaultValue(ctx, col.ToInfo())
				if err != nil {
					return false, false, 0, errors.Trace(err)
				}
			} else {
				return false, false, 0, errors.Trace(err)
			}
		}
	}

	// 3. Compare datum, then handle some flags.
	for i, col := range t.Cols() {
		cmp, err := newData[i].CompareDatum(sc, &oldData[i])
		if err != nil {
			return false, false, 0, errors.Trace(err)
		}
		if cmp != 0 {
			changed = true
			modified[i] = true
			// Rebase auto increment id if the field is changed.
			if mysql.HasAutoIncrementFlag(col.Flag) {
				if err = t.RebaseAutoID(ctx, newData[i].GetInt64(), true); err != nil {
					return false, false, 0, errors.Trace(err)
				}
			}
			if col.IsPKHandleColumn(t.Meta()) {
				handleChanged = true
				newHandle = newData[i].GetInt64()
			}
		} else {
			if mysql.HasOnUpdateNowFlag(col.Flag) && modified[i] {
				// It's for "UPDATE t SET ts = ts" and ts is a timestamp.
				onUpdateSpecified[i] = true
			}
			modified[i] = false
		}
	}

	// If no changes, nothing to do, return directly.
	if !changed {
		// See https://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html  CLIENT_FOUND_ROWS
		if ctx.GetSessionVars().ClientCapability&mysql.ClientFoundRows > 0 {
			sc.AddAffectedRows(1)
		}
		return false, false, 0, nil
	}

	// 4. Fill values into on-update-now fields, only if they are really changed.
	for i, col := range t.Cols() {
		if mysql.HasOnUpdateNowFlag(col.Flag) && !modified[i] && !onUpdateSpecified[i] {
			if v, err := expression.GetTimeValue(ctx, strings.ToUpper(ast.CurrentTimestamp), col.Tp, col.Decimal); err == nil {
				newData[i] = v
				modified[i] = true
			} else {
				return false, false, 0, errors.Trace(err)
			}
		}
	}

	// 5. If handle changed, remove the old then add the new record, otherwise update the record.
	var err error
	if handleChanged {
		skipHandleCheck := false
		if sc.DupKeyAsWarning {
			// For `UPDATE IGNORE`/`INSERT IGNORE ON DUPLICATE KEY UPDATE`
			// If the new handle exists, this will avoid to remove the record.
			err = tables.CheckHandleExists(ctx, t, newHandle, newData)
			if err != nil {
				return false, handleChanged, newHandle, errors.Trace(err)
			}
			skipHandleCheck = true
		}
		if err = t.RemoveRecord(ctx, h, oldData); err != nil {
			return false, false, 0, errors.Trace(err)
		}
		newHandle, err = t.AddRecord(ctx, newData, skipHandleCheck)
		if err != nil {
			return false, false, 0, errors.Trace(err)
		}
	} else {
		// Update record to new value and update index.
		if err = t.UpdateRecord(ctx, h, oldData, newData, modified); err != nil {
			return false, false, 0, errors.Trace(err)
		}
	}

	if onDup {
		sc.AddAffectedRows(2)
	} else {
		// if handleChanged == true, the `affectedRows` is calculated when add new record.
		if !handleChanged {
			sc.AddAffectedRows(1)
		}
	}

	// 6. Update delta for the statistics.
	colSize := make(map[int64]int64)
	for id, col := range t.Cols() {
		val := int64(len(newData[id].GetBytes()) - len(oldData[id].GetBytes()))
		if val != 0 {
			colSize[col.ID] = val
		}
	}
	ctx.GetSessionVars().TxnCtx.UpdateDeltaForTable(t.Meta().ID, 0, 1, colSize)
	return true, handleChanged, newHandle, nil
}

// resetErrDataTooLong reset ErrDataTooLong error msg.
// types.ErrDataTooLong is produced in types.ProduceStrWithSpecifiedTp, there is no column info in there,
// so we reset the error msg here, and wrap old err with errors.Wrap.
func resetErrDataTooLong(colName string, rowIdx int, err error) error {
	newErr := types.ErrDataTooLong.Gen("Data too long for column '%v' at row %v", colName, rowIdx)
	return errors.Wrap(err, newErr)
}

func getTableOffset(schema *expression.Schema, handleCol *expression.Column) int {
	for i, col := range schema.Columns {
		if col.DBName.L == handleCol.DBName.L && col.TblName.L == handleCol.TblName.L {
			return i
		}
	}
	panic("Couldn't get column information when do update/delete")
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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 tests contains test cases. To run the tests go to tests directory and run:
// RUN_TESTBED=1 go test -v

package tests

import (
	"strconv"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"go.opentelemetry.io/collector/testbed/testbed"
)

func TestIdleMode(t *testing.T) {
	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)
	tc := testbed.NewTestCase(
		t,
		dataProvider,
		testbed.NewJaegerGRPCDataSender(testbed.DefaultHost, testbed.DefaultJaegerPort),
		testbed.NewOCDataReceiver(testbed.DefaultOCPort),
		&testbed.ChildProcess{},
		&testbed.PerfTestValidator{},
		performanceResultsSummary,
	)
	defer tc.Stop()

	tc.SetResourceLimits(testbed.ResourceSpec{ExpectedMaxCPU: 4, ExpectedMaxRAM: 70})
	tc.StartAgent()

	tc.Sleep(tc.Duration)
}

func TestBallastMemory(t *testing.T) {
	tests := []struct {
		ballastSize uint32
		maxRSS      uint32
	}{
		{100, 60},
		{500, 70},
		{1000, 100},
	}

	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)
	for _, test := range tests {
		tc := testbed.NewTestCase(
			t,
			dataProvider,
			testbed.NewJaegerGRPCDataSender(testbed.DefaultHost, testbed.DefaultJaegerPort),
			testbed.NewOCDataReceiver(testbed.DefaultOCPort),
			&testbed.ChildProcess{},
			&testbed.PerfTestValidator{},
			performanceResultsSummary,
			testbed.WithSkipResults(),
		)
		tc.SetResourceLimits(testbed.ResourceSpec{ExpectedMaxRAM: test.maxRSS})

		tc.StartAgent("--mem-ballast-size-mib", strconv.Itoa(int(test.ballastSize)))

		var rss, vms uint32
		// It is possible that the process is not ready or the ballast code path
		// is not hit immediately so we give the process up to a couple of seconds
		// to fire up and setup ballast. 2 seconds is a long time for this case but
		// it is short enough to not be annoying if the test fails repeatedly
		tc.WaitForN(func() bool {
			rss, vms, _ = tc.AgentMemoryInfo()
			return vms > test.ballastSize
		}, time.Second*2, "VMS must be greater than %d", test.ballastSize)

		assert.LessOrEqual(t, rss, test.maxRSS)
		tc.Stop()
	}
}
<commit_msg>Add margin of error for TestBallastMemory (#3249)<commit_after>// Copyright The OpenTelemetry 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 tests contains test cases. To run the tests go to tests directory and run:
// RUN_TESTBED=1 go test -v

package tests

import (
	"strconv"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"go.opentelemetry.io/collector/testbed/testbed"
)

func TestIdleMode(t *testing.T) {
	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)
	tc := testbed.NewTestCase(
		t,
		dataProvider,
		testbed.NewJaegerGRPCDataSender(testbed.DefaultHost, testbed.DefaultJaegerPort),
		testbed.NewOCDataReceiver(testbed.DefaultOCPort),
		&testbed.ChildProcess{},
		&testbed.PerfTestValidator{},
		performanceResultsSummary,
	)
	defer tc.Stop()

	tc.SetResourceLimits(testbed.ResourceSpec{ExpectedMaxCPU: 4, ExpectedMaxRAM: 70})
	tc.StartAgent()

	tc.Sleep(tc.Duration)
}

func TestBallastMemory(t *testing.T) {
	tests := []struct {
		ballastSize uint32
		maxRSS      uint32
	}{
		{100, 60},
		{500, 70},
		{1000, 100},
	}

	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)
	for _, test := range tests {
		tc := testbed.NewTestCase(
			t,
			dataProvider,
			testbed.NewJaegerGRPCDataSender(testbed.DefaultHost, testbed.DefaultJaegerPort),
			testbed.NewOCDataReceiver(testbed.DefaultOCPort),
			&testbed.ChildProcess{},
			&testbed.PerfTestValidator{},
			performanceResultsSummary,
			testbed.WithSkipResults(),
		)
		tc.SetResourceLimits(testbed.ResourceSpec{ExpectedMaxRAM: test.maxRSS})

		tc.StartAgent("--mem-ballast-size-mib", strconv.Itoa(int(test.ballastSize)))

		var rss, vms uint32
		// It is possible that the process is not ready or the ballast code path
		// is not hit immediately so we give the process up to a couple of seconds
		// to fire up and setup ballast. 2 seconds is a long time for this case but
		// it is short enough to not be annoying if the test fails repeatedly
		tc.WaitForN(func() bool {
			rss, vms, _ = tc.AgentMemoryInfo()
			return vms > test.ballastSize
		}, time.Second*2, "VMS must be greater than %d", test.ballastSize)

		// https://github.com/open-telemetry/opentelemetry-collector/issues/3233
		// given that the maxRSS isn't an absolute maximum and that the actual maximum might be a bit off,
		// we give some room here instead of failing when the memory usage isn't that much higher than the max
		lenientMax := 1.1 * float32(test.maxRSS)
		assert.LessOrEqual(t, rss, lenientMax)
		tc.Stop()
	}
}
<|endoftext|>


<commit_before>package sirius

import "testing"

type ExtensionConfigAccessorTest struct {
	t   *testing.T
	f   func(string, ExtensionConfig) interface{}
	exp valueMatches
	def interface{}
}

type valueMatches map[string]interface{}

func testExtensionConfigAccessor(test ExtensionConfigAccessorTest) {
	cfg := testingExtensionConfig()

	for field := range cfg {
		a := test.f(field, cfg)

		e, match := test.exp[field]

		if match {
			if a != e {
				test.t.Errorf("Expected (%s) to resolve into %v, got %v", field, e, a)
			}
			return
		}

		if a != test.def {
			test.t.Fatalf("Expected default value %#v for (%s), got %v", test.def, field, a)
		}
	}
}

func testingExtensionConfig() ExtensionConfig {
	return ExtensionConfig{
		"int_0":        0,
		"int_1":        1,
		"float_0.0":    0.0,
		"float_1.1":    1.1,
		"bool_true":    true,
		"bool_false":   false,
		"string_hello": "hello",
		"string_empty": "",
	}

}

func TestExtensionConfig_Boolean(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Boolean(k)
		},
		exp: valueMatches{
			"int_0":      false,
			"int_1":      true,
			"bool_true":  true,
			"bool_false": false,
		},
		def: false,
	})
}

func TestExtensionConfig_Integer(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Integer(k, 999)
		},
		exp: valueMatches{
			"int_0": 0,
			"int_1": 1,
		},
		def: 999,
	})
}

func TestExtensionConfig_Float(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Float(k, 999.99)
		},
		exp: valueMatches{
			"float_0.0": 0.0,
			"float_1.1": 1.1,
		},
		def: 999.99,
	})
}

func TestExtensionConfig_String(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.String(k, "Darth Vader")
		},
		exp: valueMatches{
			"string_hello": "hello",
			"string_empty": "",
		},
		def: "Darth Vader",
	})
}

func TestExtensionConfig_Read(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Read(k, nil)
		},
		exp: valueMatches{
			"int_0":        0,
			"int_1":        1,
			"float_0.0":    0.0,
			"float_1.1":    1.1,
			"bool_true":    true,
			"bool_false":   false,
			"string_hello": "hello",
			"string_empty": "",
		},
		def: nil,
	})
}

func TestExtensionConfig_List(t *testing.T) {
	cfg := testingExtensionConfig()
	cfg["list"] = []string{"Hit", "Me", "Up"}
	cfg["list_interface"] = []interface{}{"Stop", "The", "World"}

	match := map[string][]string{
		"list":           {"Hit", "Me", "Up"},
		"list_interface": {"Stop", "The", "World"},
	}

	for field := range cfg {
		a := cfg.List(field)

		exp, ok := match[field]

		if !ok {
			if len(a) != 0 {
				t.Fatalf("Expected default value []string{} for (%s), got %v with len %v", field, a, len(a))
			}
		}

		if len(a) != len(exp) {
			t.Fatalf("Expected list of length %v, got %v", len(exp), len(a))
		}

		for i, e := range exp {
			if a[i] != e {
				t.Fatalf("Expected list item %d to be %q, got %q", i, e, a[i])
			}
		}
	}
}
<commit_msg>Add int(2) test case<commit_after>package sirius

import "testing"

type ExtensionConfigAccessorTest struct {
	t   *testing.T
	f   func(string, ExtensionConfig) interface{}
	exp valueMatches
	def interface{}
}

type valueMatches map[string]interface{}

func testExtensionConfigAccessor(test ExtensionConfigAccessorTest) {
	cfg := testingExtensionConfig()

	for field := range cfg {
		a := test.f(field, cfg)

		e, match := test.exp[field]

		if match {
			if a != e {
				test.t.Errorf("Expected (%s) to resolve into %v, got %v", field, e, a)
			}
			return
		}

		if a != test.def {
			test.t.Fatalf("Expected default value %#v for (%s), got %v", test.def, field, a)
		}
	}
}

func testingExtensionConfig() ExtensionConfig {
	return ExtensionConfig{
		"int_0":        0,
		"int_1":        1,
		"int_2":        2,
		"float_0.0":    0.0,
		"float_1.1":    1.1,
		"bool_true":    true,
		"bool_false":   false,
		"string_hello": "hello",
		"string_empty": "",
	}

}

func TestExtensionConfig_Boolean(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Boolean(k)
		},
		exp: valueMatches{
			"int_0":      false,
			"int_1":      true,
			"bool_true":  true,
			"bool_false": false,
		},
		def: false,
	})
}

func TestExtensionConfig_Integer(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Integer(k, 999)
		},
		exp: valueMatches{
			"int_0": 0,
			"int_1": 1,
			"int_2": 2,
		},
		def: 999,
	})
}

func TestExtensionConfig_Float(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Float(k, 999.99)
		},
		exp: valueMatches{
			"float_0.0": 0.0,
			"float_1.1": 1.1,
		},
		def: 999.99,
	})
}

func TestExtensionConfig_String(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.String(k, "Darth Vader")
		},
		exp: valueMatches{
			"string_hello": "hello",
			"string_empty": "",
		},
		def: "Darth Vader",
	})
}

func TestExtensionConfig_Read(t *testing.T) {
	testExtensionConfigAccessor(ExtensionConfigAccessorTest{
		t: t,
		f: func(k string, cfg ExtensionConfig) interface{} {
			return cfg.Read(k, nil)
		},
		exp: valueMatches{
			"int_0":        0,
			"int_1":        1,
			"float_0.0":    0.0,
			"float_1.1":    1.1,
			"bool_true":    true,
			"bool_false":   false,
			"string_hello": "hello",
			"string_empty": "",
		},
		def: nil,
	})
}

func TestExtensionConfig_List(t *testing.T) {
	cfg := testingExtensionConfig()
	cfg["list"] = []string{"Hit", "Me", "Up"}
	cfg["list_interface"] = []interface{}{"Stop", "The", "World"}

	match := map[string][]string{
		"list":           {"Hit", "Me", "Up"},
		"list_interface": {"Stop", "The", "World"},
	}

	for field := range cfg {
		a := cfg.List(field)

		exp, ok := match[field]

		if !ok {
			if len(a) != 0 {
				t.Fatalf("Expected default value []string{} for (%s), got %v with len %v", field, a, len(a))
			}
		}

		if len(a) != len(exp) {
			t.Fatalf("Expected list of length %v, got %v", len(exp), len(a))
		}

		for i, e := range exp {
			if a[i] != e {
				t.Fatalf("Expected list item %d to be %q, got %q", i, e, a[i])
			}
		}
	}
}
<|endoftext|>


<commit_before>package clrs

type fibNode struct {
	key    int
	p      *fibNode
	child  *fibNode
	left   *fibNode
	right  *fibNode
	degree int
	mark   bool
}

type fibHeap struct {
	min *fibNode
	n   int
}

func makeFibHeap() *fibHeap {
	return new(fibHeap)
}

func (h *fibHeap) fibHeapInsert(x *fibNode) {
	x.degree = 0
	x.p = nil
	x.child = nil
	x.mark = false
	if h.min == nil {
		x.left = x
		x.right = x
		h.min = x
	} else {
		h.listInsert(h.min, x)
		if x.key < h.min.key {
			h.min = x
		}
	}
	h.n = h.n + 1
}

func (h *fibHeap) listInsert(root, x *fibNode) {
	x.right = root
	x.left = root.left
	x.left.right = x
	root.left = x
}
<commit_msg>fibHeapUnion<commit_after>package clrs

type fibNode struct {
	key    int
	p      *fibNode
	child  *fibNode
	left   *fibNode
	right  *fibNode
	degree int
	mark   bool
}

type fibHeap struct {
	min *fibNode
	n   int
}

func makeFibHeap() *fibHeap {
	return new(fibHeap)
}

func fibHeapUnion(h1, h2 *fibHeap) *fibHeap {
	h := makeFibHeap()
	h.min = h1.min
	h.listConcatenate(h2)
	if h1.min == nil || h2.min != nil && h2.min.key < h1.min.key {
		h.min = h2.min
	}
	h.n = h1.n + h2.n
	return h
}

func (h *fibHeap) fibHeapInsert(x *fibNode) {
	x.degree = 0
	x.p = nil
	x.child = nil
	x.mark = false
	if h.min == nil {
		x.left = x
		x.right = x
		h.min = x
	} else {
		h.listInsert(h.min, x)
		if x.key < h.min.key {
			h.min = x
		}
	}
	h.n = h.n + 1
}

func (h *fibHeap) listInsert(root, x *fibNode) {
	x.right = root
	x.left = root.left
	x.left.right = x
	root.left = x
}

func (h *fibHeap) listConcatenate(h2 *fibHeap) {
	if h.min == nil {
		h.min = h2.min
	} else {
		h2.min.left.right = h.min
		h2.min.left, h.min.left = h.min.left, h2.min.left
		h2.min.left.right = h2.min
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/russross/blackfriday"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"
	"sync"
)

type FileRepository struct {
	directory string
	posts BlogPosts
	tags []string
	lastUpdated time.Time
	mutex sync.RWMutex
}

func NewFileRepository(directory string) *FileRepository {

	f := new(FileRepository)
	f.directory = directory

	f.fetchAllPosts()
	f.fetchAllTags()

	f.lastUpdated = time.Now()

	go f.update()

	return f
}

func (f *FileRepository) AllTags() []string {
	return f.tags
}

func (f *FileRepository) AllPosts() BlogPosts {
	return f.posts
}

func (f *FileRepository) PostWithUrl(url string) (*BlogPost, error) {

	f.mutex.RLock()
	defer f.mutex.RUnlock()

	for i := range f.posts {
		if f.posts[i].Url() == url {
			return f.posts[i], nil
		}
	}

	err := errors.New("Could not find post")

	return nil, err
}

func (f *FileRepository) PostsWithTag(tag string) BlogPosts {

	f.mutex.RLock()
	defer f.mutex.RUnlock()

	filteredPosts := BlogPosts{}

	for i := range f.posts {
		if f.posts[i].ContainsTag(tag) {
			filteredPosts = append(filteredPosts, f.posts[i])
		}
	}

	return filteredPosts
}

func (f *FileRepository) PostsInRange(start, count int) BlogPosts {

	f.mutex.RLock()
	defer f.mutex.RUnlock()

	if start + count > len(f.posts) {
		count = len(f.posts) - start
	}

	return f.posts[start:start + count]
}

func (f *FileRepository) update() {

	f.mutex.Lock()
	defer f.mutex.Unlock()

	for {
		f.fetchAllPosts()
		f.fetchAllTags()
		f.lastUpdated = time.Now()

		time.Sleep(10 * time.Minute)
	}
}

func (f *FileRepository) fetchAllPosts() error {

	f.mutex.Lock()
	defer f.mutex.Unlock()

	dirname := f.directory + string(filepath.Separator)

	files, err := ioutil.ReadDir(dirname)

	f.posts = BlogPosts{}

	for i := range files {

		if files[i].IsDir() {
			continue
		}

		if filepath.Ext(files[i].Name()) != ".md" {
			continue
		}

		post, err := f.fetchPost(files[i].Name())

		if err != nil {
			return err
		}

		f.posts = append(f.posts, post)
	}

	sort.Sort(f.posts)

	return err
}

func (f *FileRepository) fetchAllTags() {

	f.mutex.Lock()
	defer f.mutex.Unlock()

	// We're using a map to simulate a set
	tagMap := make(map[string]bool)

	for i := range f.posts {
		for j := range f.posts[i].Tags() {
			tagMap[strings.ToLower(f.posts[i].Tags()[j])] = true
		}
	}

	f.tags = []string{}

	for key := range tagMap {
		f.tags = append(f.tags, key)
	}

	sort.Strings(f.tags)
}

func (f *FileRepository) fetchPost(filename string) (*BlogPost, error) {

	post := new(BlogPost)

	dirname := f.directory + string(filepath.Separator)

	file, err := ioutil.ReadFile(dirname + filename)

	if err != nil {
		return post, err
	}

	file = []byte(f.extractHeader(string(file), post))

	htmlFlags := blackfriday.HTML_USE_SMARTYPANTS
	extensions := blackfriday.EXTENSION_HARD_LINE_BREAK | blackfriday.EXTENSION_FENCED_CODE | blackfriday.EXTENSION_NO_INTRA_EMPHASIS

	renderer := blackfriday.HtmlRenderer(htmlFlags, post.Title(), "")

	output := blackfriday.Markdown(file, renderer, extensions)

	post.SetBody(string(output))

	return post, nil
}

func (f *FileRepository) extractHeader(text string, post *BlogPost) string {

	lines := strings.Split(text, "\n")

	headerSize := 0

	for i := range lines {
		if strings.Contains(lines[i], ":") {
			components := strings.Split(lines[i], ":")

			header := strings.ToLower(strings.Trim(components[0], " "))
			separatorIndex := strings.Index(lines[i], ":") + 1
			data := strings.Trim(lines[i][separatorIndex:], " ")

			switch header {
			case "title":
				post.SetTitle(data)
			case "tags":

				tags := strings.Split(data, ",")

				formattedTags := []string{}

				for j := range tags {
					tags[j] = strings.Trim(tags[j], " ")
					tags[j] = strings.Replace(tags[j], " ", "-", -1)

					if tags[j] != "" {
						formattedTags = append(formattedTags, tags[j])
					}
				}

				post.SetTags(formattedTags)
			case "date":
				post.SetPublishDate(stringToTime(data))
			default:
				continue
			}

			headerSize += len(lines[i]) + 1
		} else {
			break
		}
	}

	return text[headerSize:]
}

func stringToTime(s string) time.Time {

	year, err := strconv.Atoi(s[:4])

	if err != nil {
		return time.Unix(0, 0)
	}

	month, err := strconv.Atoi(s[5:7])

	if err != nil {
		return time.Unix(0, 0)
	}

	day, err := strconv.Atoi(s[8:10])

	if err != nil {
		return time.Unix(0, 0)
	}

	hour, err := strconv.Atoi(s[11:13])

	if err != nil {
		return time.Unix(0, 0)
	}

	minute, err := strconv.Atoi(s[14:16])

	if err != nil {
		return time.Unix(0, 0)
	}

	seconds, err := strconv.Atoi(s[17:19])

	if err != nil {
		return time.Unix(0, 0)
	}

	location, err := time.LoadLocation("UTC")

	return time.Date(year, time.Month(month), day, hour, minute, seconds, 0, location)
}
<commit_msg>Mutex fix.<commit_after>package main

import (
	"errors"
	"github.com/russross/blackfriday"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"
	"sync"
)

type FileRepository struct {
	directory string
	posts BlogPosts
	tags []string
	lastUpdated time.Time
	mutex sync.RWMutex
}

func NewFileRepository(directory string) *FileRepository {

	f := new(FileRepository)
	f.directory = directory

	f.fetchAllPosts()
	f.fetchAllTags()

	f.lastUpdated = time.Now()

	go f.update()

	return f
}

func (f *FileRepository) AllTags() []string {
	return f.tags
}

func (f *FileRepository) AllPosts() BlogPosts {
	return f.posts
}

func (f *FileRepository) PostWithUrl(url string) (*BlogPost, error) {

	f.mutex.Lock()
	defer f.mutex.Unlock()

	for i := range f.posts {
		if f.posts[i].Url() == url {
			return f.posts[i], nil
		}
	}

	err := errors.New("Could not find post")

	return nil, err
}

func (f *FileRepository) PostsWithTag(tag string) BlogPosts {

	f.mutex.RLock()
	defer f.mutex.RUnlock()

	filteredPosts := BlogPosts{}

	for i := range f.posts {
		if f.posts[i].ContainsTag(tag) {
			filteredPosts = append(filteredPosts, f.posts[i])
		}
	}

	return filteredPosts
}

func (f *FileRepository) PostsInRange(start, count int) BlogPosts {

	f.mutex.RLock()
	defer f.mutex.RUnlock()

	if start + count > len(f.posts) {
		count = len(f.posts) - start
	}

	return f.posts[start:start + count]
}

func (f *FileRepository) update() {

	for {
		f.fetchAllPosts()
		f.fetchAllTags()
		f.lastUpdated = time.Now()

		time.Sleep(10 * time.Minute)
	}
}

func (f *FileRepository) fetchAllPosts() error {

	f.mutex.Lock()
	defer f.mutex.Unlock()

	dirname := f.directory + string(filepath.Separator)

	files, err := ioutil.ReadDir(dirname)

	f.posts = BlogPosts{}

	for i := range files {

		if files[i].IsDir() {
			continue
		}

		if filepath.Ext(files[i].Name()) != ".md" {
			continue
		}

		post, err := f.fetchPost(files[i].Name())

		if err != nil {
			return err
		}

		f.posts = append(f.posts, post)
	}

	sort.Sort(f.posts)

	return err
}

func (f *FileRepository) fetchAllTags() {

	f.mutex.Lock()
	defer f.mutex.Unlock()

	// We're using a map to simulate a set
	tagMap := make(map[string]bool)

	for i := range f.posts {
		for j := range f.posts[i].Tags() {
			tagMap[strings.ToLower(f.posts[i].Tags()[j])] = true
		}
	}

	f.tags = []string{}

	for key := range tagMap {
		f.tags = append(f.tags, key)
	}

	sort.Strings(f.tags)
}

func (f *FileRepository) fetchPost(filename string) (*BlogPost, error) {

	post := new(BlogPost)

	dirname := f.directory + string(filepath.Separator)

	file, err := ioutil.ReadFile(dirname + filename)

	if err != nil {
		return post, err
	}

	file = []byte(f.extractHeader(string(file), post))

	htmlFlags := blackfriday.HTML_USE_SMARTYPANTS
	extensions := blackfriday.EXTENSION_HARD_LINE_BREAK | blackfriday.EXTENSION_FENCED_CODE | blackfriday.EXTENSION_NO_INTRA_EMPHASIS

	renderer := blackfriday.HtmlRenderer(htmlFlags, post.Title(), "")

	output := blackfriday.Markdown(file, renderer, extensions)

	post.SetBody(string(output))

	return post, nil
}

func (f *FileRepository) extractHeader(text string, post *BlogPost) string {

	lines := strings.Split(text, "\n")

	headerSize := 0

	for i := range lines {
		if strings.Contains(lines[i], ":") {
			components := strings.Split(lines[i], ":")

			header := strings.ToLower(strings.Trim(components[0], " "))
			separatorIndex := strings.Index(lines[i], ":") + 1
			data := strings.Trim(lines[i][separatorIndex:], " ")

			switch header {
			case "title":
				post.SetTitle(data)
			case "tags":

				tags := strings.Split(data, ",")

				formattedTags := []string{}

				for j := range tags {
					tags[j] = strings.Trim(tags[j], " ")
					tags[j] = strings.Replace(tags[j], " ", "-", -1)

					if tags[j] != "" {
						formattedTags = append(formattedTags, tags[j])
					}
				}

				post.SetTags(formattedTags)
			case "date":
				post.SetPublishDate(stringToTime(data))
			default:
				continue
			}

			headerSize += len(lines[i]) + 1
		} else {
			break
		}
	}

	return text[headerSize:]
}

func stringToTime(s string) time.Time {

	year, err := strconv.Atoi(s[:4])

	if err != nil {
		return time.Unix(0, 0)
	}

	month, err := strconv.Atoi(s[5:7])

	if err != nil {
		return time.Unix(0, 0)
	}

	day, err := strconv.Atoi(s[8:10])

	if err != nil {
		return time.Unix(0, 0)
	}

	hour, err := strconv.Atoi(s[11:13])

	if err != nil {
		return time.Unix(0, 0)
	}

	minute, err := strconv.Atoi(s[14:16])

	if err != nil {
		return time.Unix(0, 0)
	}

	seconds, err := strconv.Atoi(s[17:19])

	if err != nil {
		return time.Unix(0, 0)
	}

	location, err := time.LoadLocation("UTC")

	return time.Date(year, time.Month(month), day, hour, minute, seconds, 0, location)
}
<|endoftext|>


<commit_before>package flatmap

import (
	"fmt"
	"strconv"
	"strings"
)

// Expand takes a map and a key (prefix) and expands that value into
// a more complex structure. This is the reverse of the Flatten operation.
func Expand(m map[string]string, key string) interface{} {
	// If the key is exactly a key in the map, just return it
	if v, ok := m[key]; ok {
		if v == "true" {
			return true
		} else if v == "false" {
			return false
		}

		return v
	}

	// Check if the key is an array, and if so, expand the array
	if _, ok := m[key+".#"]; ok {
		return expandArray(m, key)
	}

	// Check if this is a prefix in the map
	prefix := key + "."
	for k, _ := range m {
		if strings.HasPrefix(k, prefix) {
			return expandMap(m, prefix)
		}
	}

	return nil
}

func expandArray(m map[string]string, prefix string) []interface{} {
	num, err := strconv.ParseInt(m[prefix+".#"], 0, 0)
	if err != nil {
		panic(err)
	}

	result := make([]interface{}, num)
	for i := 0; i < int(num); i++ {
		result[i] = Expand(m, fmt.Sprintf("%s.%d", prefix, i))
	}

	return result
}

func expandMap(m map[string]string, prefix string) map[string]interface{} {
	result := make(map[string]interface{})
	for k, _ := range m {
		if !strings.HasPrefix(k, prefix) {
			continue
		}

		key := k[len(prefix):]
		idx := strings.Index(key, ".")
		if idx != -1 {
			key = key[:idx]
		}
		if _, ok := result[key]; ok {
			continue
		}

		// It contains a period, so it is a more complex structure
		result[key] = Expand(m, k[:len(prefix)+len(key)])
	}

	return result
}
<commit_msg>fix flatmap.Expand<commit_after>package flatmap

import (
	"fmt"
	"strconv"
	"strings"
)

// Expand takes a map and a key (prefix) and expands that value into
// a more complex structure. This is the reverse of the Flatten operation.
func Expand(m map[string]string, key string) interface{} {
	// If the key is exactly a key in the map, just return it
	if v, ok := m[key]; ok {
		if v == "true" {
			return true
		} else if v == "false" {
			return false
		}

		return v
	}

	// Check if the key is an array, and if so, expand the array
	if _, ok := m[key+".#"]; ok {
		return expandArray(m, key)
	}

	// Check if this is a prefix in the map
	prefix := key + "."
	for k, _ := range m {
		if strings.HasPrefix(k, prefix) {
			return expandMap(m, prefix)
		}
	}

	return nil
}

func expandArray(m map[string]string, prefix string) []interface{} {
	num, err := strconv.ParseInt(m[prefix+".#"], 0, 0)
	if err != nil {
		panic(err)
	}

	result := make([]interface{}, num)
	for i := 0; i < int(num); i++ {
		result[i] = Expand(m, fmt.Sprintf("%s.%d", prefix, i))
	}

	return result
}

func expandMap(m map[string]string, prefix string) map[string]interface{} {
	result := make(map[string]interface{})
	for k, _ := range m {
		if !strings.HasPrefix(k, prefix) {
			continue
		}

		key := k[len(prefix):]
		idx := strings.Index(key, ".")
		if idx != -1 {
			key = key[:idx]
		}
		if _, ok := result[key]; ok {
			continue
		}

		// skip the map count value
		if key == "%" {
			continue
		}
		result[key] = Expand(m, k[:len(prefix)+len(key)])
	}

	return result
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative 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 v1alpha1

import (
	"github.com/knative/pkg/apis"
	duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1"
	"github.com/knative/pkg/webhook"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Check that Task may be validated and defaulted.
var _ apis.Validatable = (*TaskRun)(nil)
var _ apis.Defaultable = (*TaskRun)(nil)

// Assert that Task implements the GenericCRD interface.
var _ webhook.GenericCRD = (*TaskRun)(nil)

// TaskRunSpec defines the desired state of TaskRun
type TaskRunSpec struct {
	TaskRef TaskRef     `json:"taskRef"`
	Trigger TaskTrigger `json:"trigger"`
	// +optional
	Inputs TaskRunInputs `json:"inputs,omitempty"`
	// +optional
	Outputs Outputs `json:"outputs,omitempty"`
	Results Results `json:"results"`
}

// TaskRunInputs holds the input values that this task was invoked with.
type TaskRunInputs struct {
	// +optional
	Resources []PipelineResourceVersion `json:"resourcesVersion,omitempty"`
	// +optional
	Params []Param `json:"params,omitempty"`
}

// TaskTrigger defines a webhook style trigger to start a TaskRun
type TaskTrigger struct {
	TriggerRef TaskTriggerRef `json:"triggerRef"`
}

// TaskTriggerType indicates the mechanism by which this TaskRun was created.
type TaskTriggerType string

const (
	// TaskTriggerTypeManual indicates that this TaskRun was invoked manually by a user.
	TaskTriggerTypeManual TaskTriggerType = "manual"

	// TaskTriggerTypePipelineRun indicates that this TaskRun was created by a controller
	// attempting to realize a PipelineRun. In this case the `name` will refer to the name
	// of the PipelineRun.
	TaskTriggerTypePipelineRun TaskTriggerType = "pipelineRun"
)

// TaskTriggerRef describes what triggered this Task to run. It could be triggered manually,
// or it may have been part of a PipelineRun in which case this ref would refer
// to the corresponding PipelineRun.
type TaskTriggerRef struct {
	Type TaskTriggerType `json:"type"`
	// +optional
	Name string `json:"name,omitempty"`
}

// TaskRunStatus defines the observed state of TaskRun
type TaskRunStatus struct {
	Steps []StepRun `json:"steps"`
	// Conditions describes the set of conditions of this build.
	Conditions duckv1alpha1.Conditions `json:"conditions,omitempty"`
}

var taskRunCondSet = duckv1alpha1.NewBatchConditionSet()

// GetCondition returns the Condition matching the given type.
func (tr *TaskRunStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition {
	return taskRunCondSet.Manage(tr).GetCondition(t)
}

// SetCondition sets the condition, unsetting previous conditions with the same
// type as necessary.
func (bs *TaskRunStatus) SetCondition(newCond *duckv1alpha1.Condition) {
	if newCond != nil {
		taskRunCondSet.Manage(bs).SetCondition(*newCond)
	}
}

// StepRun reports the results of running a step in the Task. Each
// task has the potential to succeed or fail (based on the exit code)
// and produces logs.
type StepRun struct {
	Name     string `json:"name"`
	LogsURL  string `json:"logsURL"`
	ExitCode int    `json:"exitCode"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// TaskRun is the Schema for the taskruns API
// +k8s:openapi-gen=true
type TaskRun struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty"`

	// +optional
	Spec TaskRunSpec `json:"spec,omitempty"`
	// +optional
	Status TaskRunStatus `json:"status,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// TaskRunList contains a list of TaskRun
type TaskRunList struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []TaskRun `json:"items"`
}

func (t *TaskRun) SetDefaults() {}
<commit_msg>Add generation to avoid webhook crashloop<commit_after>/*
Copyright 2018 The Knative 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 v1alpha1

import (
	"github.com/knative/pkg/apis"
	duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1"
	"github.com/knative/pkg/webhook"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Check that Task may be validated and defaulted.
var _ apis.Validatable = (*TaskRun)(nil)
var _ apis.Defaultable = (*TaskRun)(nil)

// Assert that Task implements the GenericCRD interface.
var _ webhook.GenericCRD = (*TaskRun)(nil)

// TaskRunSpec defines the desired state of TaskRun
type TaskRunSpec struct {
	TaskRef TaskRef     `json:"taskRef"`
	Trigger TaskTrigger `json:"trigger"`
	// +optional
	Inputs TaskRunInputs `json:"inputs,omitempty"`
	// +optional
	Outputs Outputs `json:"outputs,omitempty"`
	Results Results `json:"results"`
	// +optional
	Generation int64 `json:"generation,omitempty"`
}

// TaskRunInputs holds the input values that this task was invoked with.
type TaskRunInputs struct {
	// +optional
	Resources []PipelineResourceVersion `json:"resourcesVersion,omitempty"`
	// +optional
	Params []Param `json:"params,omitempty"`
}

// TaskTrigger defines a webhook style trigger to start a TaskRun
type TaskTrigger struct {
	TriggerRef TaskTriggerRef `json:"triggerRef"`
}

// TaskTriggerType indicates the mechanism by which this TaskRun was created.
type TaskTriggerType string

const (
	// TaskTriggerTypeManual indicates that this TaskRun was invoked manually by a user.
	TaskTriggerTypeManual TaskTriggerType = "manual"

	// TaskTriggerTypePipelineRun indicates that this TaskRun was created by a controller
	// attempting to realize a PipelineRun. In this case the `name` will refer to the name
	// of the PipelineRun.
	TaskTriggerTypePipelineRun TaskTriggerType = "pipelineRun"
)

// TaskTriggerRef describes what triggered this Task to run. It could be triggered manually,
// or it may have been part of a PipelineRun in which case this ref would refer
// to the corresponding PipelineRun.
type TaskTriggerRef struct {
	Type TaskTriggerType `json:"type"`
	// +optional
	Name string `json:"name,omitempty"`
}

// TaskRunStatus defines the observed state of TaskRun
type TaskRunStatus struct {
	Steps []StepRun `json:"steps"`
	// Conditions describes the set of conditions of this build.
	Conditions duckv1alpha1.Conditions `json:"conditions,omitempty"`
}

var taskRunCondSet = duckv1alpha1.NewBatchConditionSet()

// GetCondition returns the Condition matching the given type.
func (tr *TaskRunStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition {
	return taskRunCondSet.Manage(tr).GetCondition(t)
}

// SetCondition sets the condition, unsetting previous conditions with the same
// type as necessary.
func (bs *TaskRunStatus) SetCondition(newCond *duckv1alpha1.Condition) {
	if newCond != nil {
		taskRunCondSet.Manage(bs).SetCondition(*newCond)
	}
}

// StepRun reports the results of running a step in the Task. Each
// task has the potential to succeed or fail (based on the exit code)
// and produces logs.
type StepRun struct {
	Name     string `json:"name"`
	LogsURL  string `json:"logsURL"`
	ExitCode int    `json:"exitCode"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// TaskRun is the Schema for the taskruns API
// +k8s:openapi-gen=true
type TaskRun struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty"`

	// +optional
	Spec TaskRunSpec `json:"spec,omitempty"`
	// +optional
	Status TaskRunStatus `json:"status,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// TaskRunList contains a list of TaskRun
type TaskRunList struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []TaskRun `json:"items"`
}

func (t *TaskRun) SetDefaults() {}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 controller

import (
	"crypto/x509"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/golang/glog"

	apiv1 "k8s.io/api/core/v1"
	extensions "k8s.io/api/extensions/v1beta1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/scheme"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/flowcontrol"

	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/net/ssl"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/task"
)

// GenericController holds the boilerplate code required to build an Ingress controlller.
type GenericController struct {
	cfg             *Configuration
	listers         *ingress.StoreLister
	cacheController *cacheController
	recorder        record.EventRecorder
	syncQueue       *task.Queue
	syncStatus      StatusSync
	sslCertTracker  *sslCertTracker
	syncRateLimiter flowcontrol.RateLimiter
	stopLock        *sync.Mutex
	stopCh          chan struct{}
}

// Configuration contains all the settings required by an Ingress controller
type Configuration struct {
	Client clientset.Interface

	RateLimitUpdate float32
	ResyncPeriod    time.Duration

	DefaultService string
	IngressClass   string
	WatchNamespace string
	ConfigMapName  string

	ForceNamespaceIsolation bool
	WaitBeforeShutdown      int
	AllowCrossNamespace     bool
	DisableNodeList         bool
	AnnPrefix               string

	AcmeServer              bool
	AcmeCheckPeriod         time.Duration
	AcmeFailInitialDuration time.Duration
	AcmeFailMaxDuration     time.Duration
	AcmeElectionID          string
	AcmeSecretKeyName       string
	AcmeTokenConfigmapName  string
	AcmeTrackTLSAnn         bool

	BucketsResponseTime []float64

	TCPConfigMapName       string
	DefaultSSLCertificate  string
	VerifyHostname         bool
	DefaultHealthzURL      string
	StatsCollectProcPeriod time.Duration
	PublishService         string
	Backend                ingress.Controller

	UpdateStatus           bool
	UseNodeInternalIP      bool
	ElectionID             string
	UpdateStatusOnShutdown bool

	SortBackends              bool
	IgnoreIngressWithoutClass bool
}

// newIngressController creates an Ingress controller
func newIngressController(config *Configuration) *GenericController {

	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartLogging(glog.Infof)
	eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{
		Interface: config.Client.CoreV1().Events(config.WatchNamespace),
	})

	ic := GenericController{
		cfg:             config,
		stopLock:        &sync.Mutex{},
		stopCh:          make(chan struct{}),
		syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(config.RateLimitUpdate, 1),
		recorder: eventBroadcaster.NewRecorder(scheme.Scheme, apiv1.EventSource{
			Component: "ingress-controller",
		}),
		sslCertTracker: newSSLCertTracker(),
	}

	ic.syncQueue = task.NewTaskQueue(ic.syncIngress)

	ic.listers, ic.cacheController = ic.createListers(config.DisableNodeList)

	if config.UpdateStatus {
		ic.syncStatus = NewStatusSyncer(&ic)
	} else {
		glog.Warning("Update of ingress status is disabled (flag --update-status=false was specified)")
	}

	ic.cfg.Backend.SetListers(ic.listers)

	return &ic
}

// IngressClassKey ...
const IngressClassKey = "kubernetes.io/ingress.class"

// IsValidClass ...
func (ic *GenericController) IsValidClass(ing *extensions.Ingress) bool {
	ann, found := ing.Annotations[IngressClassKey]

	if ic.cfg.IgnoreIngressWithoutClass {
		return found && ann == ic.cfg.IngressClass
	}

	return !found || ann == ic.cfg.IngressClass
}

// GetConfig expose the controller configuration
func (ic *GenericController) GetConfig() *Configuration {
	return ic.cfg
}

// GetStopCh ...
func (ic *GenericController) GetStopCh() chan struct{} {
	return ic.stopCh
}

// Info returns information about the backend
func (ic GenericController) Info() *ingress.BackendInfo {
	return ic.cfg.Backend.Info()
}

// sync collects all the pieces required to assemble the configuration file and
// then sends the content to the backend (OnUpdate) receiving the populated
// template as response reloading the backend if is required.
func (ic *GenericController) syncIngress(item interface{}) error {
	if !ic.syncQueue.IsShuttingDown() {
		ic.syncRateLimiter.Accept()
		ic.cfg.Backend.SyncIngress(item)
	}
	return nil
}

// GetCertificate get a SSLCert object from a secret name
func (ic *GenericController) GetCertificate(name string) (*ingress.SSLCert, error) {
	crt, exists := ic.sslCertTracker.Get(name)
	if !exists {
		ic.syncSecret(name)
		crt, exists = ic.sslCertTracker.Get(name)
	}
	if exists {
		return crt.(*ingress.SSLCert), nil
	}
	if _, err := ic.listers.Secret.GetByName(name); err != nil {
		return nil, err
	}
	return nil, fmt.Errorf("secret '%v' have neither ca.crt nor tls.crt/tls.key pair", name)
}

// GetFullResourceName add the currentNamespace prefix if name doesn't provide one
// and AllowCrossNamespace is allowing this
func (ic GenericController) GetFullResourceName(name, currentNamespace string) string {
	if name == "" {
		return ""
	}
	if strings.Index(name, "/") == -1 {
		// there isn't a slash, just the resourcename
		return fmt.Sprintf("%v/%v", currentNamespace, name)
	} else if !ic.cfg.AllowCrossNamespace {
		// there IS a slash: namespace/resourcename
		// and cross namespace isn't allowed
		ns := strings.Split(name, "/")[0]
		if ns != currentNamespace {
			// concat currentNamespace in order to fail resource reading
			return fmt.Sprintf("%v/%v", currentNamespace, name)
		}
	}
	return name
}

// Stop stops the loadbalancer controller.
func (ic GenericController) Stop() error {
	ic.stopLock.Lock()
	defer ic.stopLock.Unlock()

	// Only try draining the workqueue if we haven't already.
	if !ic.syncQueue.IsShuttingDown() {
		glog.Infof("shutting down controller queues")
		close(ic.stopCh)
		go ic.syncQueue.Shutdown()
		if ic.syncStatus != nil {
			ic.syncStatus.Shutdown()
		}
		return nil
	}

	return fmt.Errorf("shutdown already in progress")
}

// StartControllers ...
func (ic *GenericController) StartControllers() {
	ic.cacheController.Run(ic.stopCh)
}

// Start starts the Ingress controller.
func (ic *GenericController) Start() {
	glog.Infof("starting Ingress controller")

	go ic.syncQueue.Run(time.Second, ic.stopCh)

	if ic.syncStatus != nil {
		go ic.syncStatus.Run(ic.stopCh)
	}

	// force initial sync
	ic.syncQueue.Enqueue(&extensions.Ingress{})

	<-ic.stopCh
}

// CreateDefaultSSLCertificate ...
func (ic *GenericController) CreateDefaultSSLCertificate() (path, hash string, crt *x509.Certificate) {
	defCert, defKey := ssl.GetFakeSSLCert(
		[]string{"Acme Co"}, "Kubernetes Ingress Controller Fake Certificate", []string{"ingress.local"},
	)
	c, err := ssl.AddOrUpdateCertAndKey("default-fake-certificate", defCert, defKey, []byte{})
	if err != nil {
		glog.Fatalf("Error generating self signed certificate: %v", err)
	}
	return c.PemFileName, c.PemSHA, c.Certificate
}
<commit_msg>Typo on doc variable name<commit_after>/*
Copyright 2015 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 controller

import (
	"crypto/x509"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/golang/glog"

	apiv1 "k8s.io/api/core/v1"
	extensions "k8s.io/api/extensions/v1beta1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/scheme"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/flowcontrol"

	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/net/ssl"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/task"
)

// GenericController holds the boilerplate code required to build an Ingress controlller.
type GenericController struct {
	cfg             *Configuration
	listers         *ingress.StoreLister
	cacheController *cacheController
	recorder        record.EventRecorder
	syncQueue       *task.Queue
	syncStatus      StatusSync
	sslCertTracker  *sslCertTracker
	syncRateLimiter flowcontrol.RateLimiter
	stopLock        *sync.Mutex
	stopCh          chan struct{}
}

// Configuration contains all the settings required by an Ingress controller
type Configuration struct {
	Client clientset.Interface

	RateLimitUpdate float32
	ResyncPeriod    time.Duration

	DefaultService string
	IngressClass   string
	WatchNamespace string
	ConfigMapName  string

	ForceNamespaceIsolation bool
	WaitBeforeShutdown      int
	AllowCrossNamespace     bool
	DisableNodeList         bool
	AnnPrefix               string

	AcmeServer              bool
	AcmeCheckPeriod         time.Duration
	AcmeFailInitialDuration time.Duration
	AcmeFailMaxDuration     time.Duration
	AcmeElectionID          string
	AcmeSecretKeyName       string
	AcmeTokenConfigmapName  string
	AcmeTrackTLSAnn         bool

	BucketsResponseTime []float64

	TCPConfigMapName       string
	DefaultSSLCertificate  string
	VerifyHostname         bool
	DefaultHealthzURL      string
	StatsCollectProcPeriod time.Duration
	PublishService         string
	Backend                ingress.Controller

	UpdateStatus           bool
	UseNodeInternalIP      bool
	ElectionID             string
	UpdateStatusOnShutdown bool

	SortBackends              bool
	IgnoreIngressWithoutClass bool
}

// newIngressController creates an Ingress controller
func newIngressController(config *Configuration) *GenericController {

	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartLogging(glog.Infof)
	eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{
		Interface: config.Client.CoreV1().Events(config.WatchNamespace),
	})

	ic := GenericController{
		cfg:             config,
		stopLock:        &sync.Mutex{},
		stopCh:          make(chan struct{}),
		syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(config.RateLimitUpdate, 1),
		recorder: eventBroadcaster.NewRecorder(scheme.Scheme, apiv1.EventSource{
			Component: "ingress-controller",
		}),
		sslCertTracker: newSSLCertTracker(),
	}

	ic.syncQueue = task.NewTaskQueue(ic.syncIngress)

	ic.listers, ic.cacheController = ic.createListers(config.DisableNodeList)

	if config.UpdateStatus {
		ic.syncStatus = NewStatusSyncer(&ic)
	} else {
		glog.Warning("Update of ingress status is disabled (flag --update-status=false was specified)")
	}

	ic.cfg.Backend.SetListers(ic.listers)

	return &ic
}

// IngressClassKey ...
const IngressClassKey = "kubernetes.io/ingress.class"

// IsValidClass ...
func (ic *GenericController) IsValidClass(ing *extensions.Ingress) bool {
	ann, found := ing.Annotations[IngressClassKey]

	if ic.cfg.IgnoreIngressWithoutClass {
		return found && ann == ic.cfg.IngressClass
	}

	return !found || ann == ic.cfg.IngressClass
}

// GetConfig expose the controller configuration
func (ic *GenericController) GetConfig() *Configuration {
	return ic.cfg
}

// GetStopCh ...
func (ic *GenericController) GetStopCh() chan struct{} {
	return ic.stopCh
}

// Info returns information about the backend
func (ic GenericController) Info() *ingress.BackendInfo {
	return ic.cfg.Backend.Info()
}

// sync collects all the pieces required to assemble the configuration file and
// then sends the content to the backend (OnUpdate) receiving the populated
// template as response reloading the backend if is required.
func (ic *GenericController) syncIngress(item interface{}) error {
	if !ic.syncQueue.IsShuttingDown() {
		ic.syncRateLimiter.Accept()
		ic.cfg.Backend.SyncIngress(item)
	}
	return nil
}

// GetCertificate get a SSLCert object from a secret name
func (ic *GenericController) GetCertificate(name string) (*ingress.SSLCert, error) {
	crt, exists := ic.sslCertTracker.Get(name)
	if !exists {
		ic.syncSecret(name)
		crt, exists = ic.sslCertTracker.Get(name)
	}
	if exists {
		return crt.(*ingress.SSLCert), nil
	}
	if _, err := ic.listers.Secret.GetByName(name); err != nil {
		return nil, err
	}
	return nil, fmt.Errorf("secret '%v' have neither ca.crt nor tls.crt/tls.key pair", name)
}

// GetFullResourceName add the currentNamespace prefix if name doesn't provide one
// and AllowCrossNamespace is allowing this
func (ic GenericController) GetFullResourceName(name, currentNamespace string) string {
	if name == "" {
		return ""
	}
	if strings.Index(name, "/") == -1 {
		// there isn't a slash, just the resource name
		return fmt.Sprintf("%v/%v", currentNamespace, name)
	} else if !ic.cfg.AllowCrossNamespace {
		// there IS a slash: namespace/resourcename
		// and cross namespace isn't allowed
		ns := strings.Split(name, "/")[0]
		if ns != currentNamespace {
			// concat currentNamespace in order to fail resource reading
			return fmt.Sprintf("%v/%v", currentNamespace, name)
		}
	}
	return name
}

// Stop stops the loadbalancer controller.
func (ic GenericController) Stop() error {
	ic.stopLock.Lock()
	defer ic.stopLock.Unlock()

	// Only try draining the workqueue if we haven't already.
	if !ic.syncQueue.IsShuttingDown() {
		glog.Infof("shutting down controller queues")
		close(ic.stopCh)
		go ic.syncQueue.Shutdown()
		if ic.syncStatus != nil {
			ic.syncStatus.Shutdown()
		}
		return nil
	}

	return fmt.Errorf("shutdown already in progress")
}

// StartControllers ...
func (ic *GenericController) StartControllers() {
	ic.cacheController.Run(ic.stopCh)
}

// Start starts the Ingress controller.
func (ic *GenericController) Start() {
	glog.Infof("starting Ingress controller")

	go ic.syncQueue.Run(time.Second, ic.stopCh)

	if ic.syncStatus != nil {
		go ic.syncStatus.Run(ic.stopCh)
	}

	// force initial sync
	ic.syncQueue.Enqueue(&extensions.Ingress{})

	<-ic.stopCh
}

// CreateDefaultSSLCertificate ...
func (ic *GenericController) CreateDefaultSSLCertificate() (path, hash string, crt *x509.Certificate) {
	defCert, defKey := ssl.GetFakeSSLCert(
		[]string{"Acme Co"}, "Kubernetes Ingress Controller Fake Certificate", []string{"ingress.local"},
	)
	c, err := ssl.AddOrUpdateCertAndKey("default-fake-certificate", defCert, defKey, []byte{})
	if err != nil {
		glog.Fatalf("Error generating self signed certificate: %v", err)
	}
	return c.PemFileName, c.PemSHA, c.Certificate
}
<|endoftext|>