<commit_before>package common

import (
	"fmt"
	"log"
	"regexp"

	"github.com/hashicorp/packer/template/interpolate"
)

// AMIConfig is for common configuration related to creating AMIs.
type AMIConfig struct {
	AMIName                 string            `mapstructure:"ami_name"`
	AMIDescription          string            `mapstructure:"ami_description"`
	AMIVirtType             string            `mapstructure:"ami_virtualization_type"`
	AMIUsers                []string          `mapstructure:"ami_users"`
	AMIGroups               []string          `mapstructure:"ami_groups"`
	AMIProductCodes         []string          `mapstructure:"ami_product_codes"`
	AMIRegions              []string          `mapstructure:"ami_regions"`
	AMISkipRegionValidation bool              `mapstructure:"skip_region_validation"`
	AMITags                 TagMap            `mapstructure:"tags"`
	AMIENASupport           *bool             `mapstructure:"ena_support"`
	AMISriovNetSupport      bool              `mapstructure:"sriov_support"`
	AMIForceDeregister      bool              `mapstructure:"force_deregister"`
	AMIForceDeleteSnapshot  bool              `mapstructure:"force_delete_snapshot"`
	AMIEncryptBootVolume    *bool             `mapstructure:"encrypt_boot"`
	AMIKmsKeyId             string            `mapstructure:"kms_key_id"`
	AMIRegionKMSKeyIDs      map[string]string `mapstructure:"region_kms_key_ids"`
	SnapshotTags            TagMap            `mapstructure:"snapshot_tags"`
	SnapshotUsers           []string          `mapstructure:"snapshot_users"`
	SnapshotGroups          []string          `mapstructure:"snapshot_groups"`
}

func stringInSlice(s []string, searchstr string) bool {
	for _, item := range s {
		if item == searchstr {
			return true
		}
	}
	return false
}

func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context) []error {
	var errs []error

	if c.AMIName == "" {
		errs = append(errs, fmt.Errorf("ami_name must be specified"))
	}

	// Make sure that if we have region_kms_key_ids defined,
	//  the regions in region_kms_key_ids are also in ami_regions
	if len(c.AMIRegionKMSKeyIDs) > 0 {
		for kmsKeyRegion := range c.AMIRegionKMSKeyIDs {
			if !stringInSlice(c.AMIRegions, kmsKeyRegion) {
				errs = append(errs, fmt.Errorf("Region %s is in region_kms_key_ids but not in ami_regions", kmsKeyRegion))
			}
		}
	}

	errs = append(errs, c.prepareRegions(accessConfig)...)

    // Prevent sharing of default KMS key encrypted volumes with other aws users
	if len(c.AMIUsers) > 0 {
		if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
			errs = append(errs, fmt.Errorf("Cannot share AMI encrypted with default KMS key"))
		}
		if len(c.AMIRegionKMSKeyIDs) > 0 {
			for _, kmsKey := range c.AMIRegionKMSKeyIDs {
				if len(kmsKey) == 0 {
					errs = append(errs, fmt.Errorf("Cannot share AMI encrypted with default KMS key for other regions"))
				}
			}
		}
	}

	var kmsKeys []string
	if len(c.AMIKmsKeyId) > 0 {
		kmsKeys = append(kmsKeys, c.AMIKmsKeyId)
	}
	if len(c.AMIRegionKMSKeyIDs) > 0 {
		for _, kmsKey := range c.AMIRegionKMSKeyIDs {
			if len(kmsKey) == 0 {
				kmsKeys = append(kmsKeys, c.AMIKmsKeyId)
			}
		}
	}
	for _, kmsKey := range kmsKeys {
		if !validateKmsKey(kmsKey) {
			errs = append(errs, fmt.Errorf("%s is not a valid KMS Key Id.", kmsKey))
		}
	}

	if len(c.SnapshotUsers) > 0 {
		if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
			errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
		}
		if len(c.AMIRegionKMSKeyIDs) > 0 {
			for _, kmsKey := range c.AMIRegionKMSKeyIDs {
				if len(kmsKey) == 0 {
					errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
				}
			}
		}
	}

	if len(c.AMIName) < 3 || len(c.AMIName) > 128 {
		errs = append(errs, fmt.Errorf("ami_name must be between 3 and 128 characters long"))
	}

	if c.AMIName != templateCleanAMIName(c.AMIName) {
		errs = append(errs, fmt.Errorf("AMIName should only contain "+
			"alphanumeric characters, parentheses (()), square brackets ([]), spaces "+
			"( ), periods (.), slashes (/), dashes (-), single quotes ('), at-signs "+
			"(@), or underscores(_). You can use the `clean_resource_name` template "+
			"filter to automatically clean your ami name."))
	}

	if len(errs) > 0 {
		return errs
	}

	return nil
}

func (c *AMIConfig) prepareRegions(accessConfig *AccessConfig) (errs []error) {
	if len(c.AMIRegions) > 0 {
		regionSet := make(map[string]struct{})
		regions := make([]string, 0, len(c.AMIRegions))

		for _, region := range c.AMIRegions {
			// If we already saw the region, then don't look again
			if _, ok := regionSet[region]; ok {
				continue
			}

			// Mark that we saw the region
			regionSet[region] = struct{}{}

			// Make sure that if we have region_kms_key_ids defined,
			// the regions in ami_regions are also in region_kms_key_ids
			if len(c.AMIRegionKMSKeyIDs) > 0 {
				if _, ok := c.AMIRegionKMSKeyIDs[region]; !ok {
					errs = append(errs, fmt.Errorf("Region %s is in ami_regions but not in region_kms_key_ids", region))
				}
			}
			if (accessConfig != nil) && (region == accessConfig.RawRegion) {
				// make sure we don't try to copy to the region we originally
				// create the AMI in.
				log.Printf("Cannot copy AMI to AWS session region '%s', deleting it from `ami_regions`.", region)
				continue
			}
			regions = append(regions, region)
		}

		c.AMIRegions = regions
	}
	return errs
}

// See https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html
func validateKmsKey(kmsKey string) (valid bool) {
	kmsKeyIdPattern := `[a-f0-9-]+$`
	aliasPattern := `alias/[a-zA-Z0-9:/_-]+$`
	kmsArnStartPattern := `^arn:aws(-us-gov)?:kms:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12}):`
	if regexp.MustCompile(fmt.Sprintf("^%s", kmsKeyIdPattern)).MatchString(kmsKey) {
		return true
	}
	if regexp.MustCompile(fmt.Sprintf("^%s", aliasPattern)).MatchString(kmsKey) {
		return true
	}
	if regexp.MustCompile(fmt.Sprintf("%skey/%s", kmsArnStartPattern, kmsKeyIdPattern)).MatchString(kmsKey) {
		return true
	}
	if regexp.MustCompile(fmt.Sprintf("%s%s", kmsArnStartPattern, aliasPattern)).MatchString(kmsKey) {
		return true
	}
	return false
}
<commit_msg>Fixed spacing on comment<commit_after>package common

import (
	"fmt"
	"log"
	"regexp"

	"github.com/hashicorp/packer/template/interpolate"
)

// AMIConfig is for common configuration related to creating AMIs.
type AMIConfig struct {
	AMIName                 string            `mapstructure:"ami_name"`
	AMIDescription          string            `mapstructure:"ami_description"`
	AMIVirtType             string            `mapstructure:"ami_virtualization_type"`
	AMIUsers                []string          `mapstructure:"ami_users"`
	AMIGroups               []string          `mapstructure:"ami_groups"`
	AMIProductCodes         []string          `mapstructure:"ami_product_codes"`
	AMIRegions              []string          `mapstructure:"ami_regions"`
	AMISkipRegionValidation bool              `mapstructure:"skip_region_validation"`
	AMITags                 TagMap            `mapstructure:"tags"`
	AMIENASupport           *bool             `mapstructure:"ena_support"`
	AMISriovNetSupport      bool              `mapstructure:"sriov_support"`
	AMIForceDeregister      bool              `mapstructure:"force_deregister"`
	AMIForceDeleteSnapshot  bool              `mapstructure:"force_delete_snapshot"`
	AMIEncryptBootVolume    *bool             `mapstructure:"encrypt_boot"`
	AMIKmsKeyId             string            `mapstructure:"kms_key_id"`
	AMIRegionKMSKeyIDs      map[string]string `mapstructure:"region_kms_key_ids"`
	SnapshotTags            TagMap            `mapstructure:"snapshot_tags"`
	SnapshotUsers           []string          `mapstructure:"snapshot_users"`
	SnapshotGroups          []string          `mapstructure:"snapshot_groups"`
}

func stringInSlice(s []string, searchstr string) bool {
	for _, item := range s {
		if item == searchstr {
			return true
		}
	}
	return false
}

func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context) []error {
	var errs []error

	if c.AMIName == "" {
		errs = append(errs, fmt.Errorf("ami_name must be specified"))
	}

	// Make sure that if we have region_kms_key_ids defined,
	//  the regions in region_kms_key_ids are also in ami_regions
	if len(c.AMIRegionKMSKeyIDs) > 0 {
		for kmsKeyRegion := range c.AMIRegionKMSKeyIDs {
			if !stringInSlice(c.AMIRegions, kmsKeyRegion) {
				errs = append(errs, fmt.Errorf("Region %s is in region_kms_key_ids but not in ami_regions", kmsKeyRegion))
			}
		}
	}

	errs = append(errs, c.prepareRegions(accessConfig)...)

	// Prevent sharing of default KMS key encrypted volumes with other aws users
	if len(c.AMIUsers) > 0 {
		if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
			errs = append(errs, fmt.Errorf("Cannot share AMI encrypted with default KMS key"))
		}
		if len(c.AMIRegionKMSKeyIDs) > 0 {
			for _, kmsKey := range c.AMIRegionKMSKeyIDs {
				if len(kmsKey) == 0 {
					errs = append(errs, fmt.Errorf("Cannot share AMI encrypted with default KMS key for other regions"))
				}
			}
		}
	}

	var kmsKeys []string
	if len(c.AMIKmsKeyId) > 0 {
		kmsKeys = append(kmsKeys, c.AMIKmsKeyId)
	}
	if len(c.AMIRegionKMSKeyIDs) > 0 {
		for _, kmsKey := range c.AMIRegionKMSKeyIDs {
			if len(kmsKey) == 0 {
				kmsKeys = append(kmsKeys, c.AMIKmsKeyId)
			}
		}
	}
	for _, kmsKey := range kmsKeys {
		if !validateKmsKey(kmsKey) {
			errs = append(errs, fmt.Errorf("%s is not a valid KMS Key Id.", kmsKey))
		}
	}

	if len(c.SnapshotUsers) > 0 {
		if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
			errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
		}
		if len(c.AMIRegionKMSKeyIDs) > 0 {
			for _, kmsKey := range c.AMIRegionKMSKeyIDs {
				if len(kmsKey) == 0 {
					errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
				}
			}
		}
	}

	if len(c.AMIName) < 3 || len(c.AMIName) > 128 {
		errs = append(errs, fmt.Errorf("ami_name must be between 3 and 128 characters long"))
	}

	if c.AMIName != templateCleanAMIName(c.AMIName) {
		errs = append(errs, fmt.Errorf("AMIName should only contain "+
			"alphanumeric characters, parentheses (()), square brackets ([]), spaces "+
			"( ), periods (.), slashes (/), dashes (-), single quotes ('), at-signs "+
			"(@), or underscores(_). You can use the `clean_resource_name` template "+
			"filter to automatically clean your ami name."))
	}

	if len(errs) > 0 {
		return errs
	}

	return nil
}

func (c *AMIConfig) prepareRegions(accessConfig *AccessConfig) (errs []error) {
	if len(c.AMIRegions) > 0 {
		regionSet := make(map[string]struct{})
		regions := make([]string, 0, len(c.AMIRegions))

		for _, region := range c.AMIRegions {
			// If we already saw the region, then don't look again
			if _, ok := regionSet[region]; ok {
				continue
			}

			// Mark that we saw the region
			regionSet[region] = struct{}{}

			// Make sure that if we have region_kms_key_ids defined,
			// the regions in ami_regions are also in region_kms_key_ids
			if len(c.AMIRegionKMSKeyIDs) > 0 {
				if _, ok := c.AMIRegionKMSKeyIDs[region]; !ok {
					errs = append(errs, fmt.Errorf("Region %s is in ami_regions but not in region_kms_key_ids", region))
				}
			}
			if (accessConfig != nil) && (region == accessConfig.RawRegion) {
				// make sure we don't try to copy to the region we originally
				// create the AMI in.
				log.Printf("Cannot copy AMI to AWS session region '%s', deleting it from `ami_regions`.", region)
				continue
			}
			regions = append(regions, region)
		}

		c.AMIRegions = regions
	}
	return errs
}

// See https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html
func validateKmsKey(kmsKey string) (valid bool) {
	kmsKeyIdPattern := `[a-f0-9-]+$`
	aliasPattern := `alias/[a-zA-Z0-9:/_-]+$`
	kmsArnStartPattern := `^arn:aws(-us-gov)?:kms:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12}):`
	if regexp.MustCompile(fmt.Sprintf("^%s", kmsKeyIdPattern)).MatchString(kmsKey) {
		return true
	}
	if regexp.MustCompile(fmt.Sprintf("^%s", aliasPattern)).MatchString(kmsKey) {
		return true
	}
	if regexp.MustCompile(fmt.Sprintf("%skey/%s", kmsArnStartPattern, kmsKeyIdPattern)).MatchString(kmsKey) {
		return true
	}
	if regexp.MustCompile(fmt.Sprintf("%s%s", kmsArnStartPattern, aliasPattern)).MatchString(kmsKey) {
		return true
	}
	return false
}
<|endoftext|>


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

package main

import (
	"github.com/spf13/cobra"
	"golang.org/x/sync/errgroup"

	"github.com/pulcy/quark/providers"
)

var (
	cmdCreateInstance = &cobra.Command{
		Use: "create",
		Run: createInstance,
	}

	createInstanceFlags providers.CreateInstanceOptions
)

func init() {
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.Domain, "domain", defaultDomain(), "Cluster domain")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.Name, "name", "", "Cluster name")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.ImageID, "image", "", "OS image to run on new instances")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.RegionID, "region", "", "Region to create the instances in")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.TypeID, "type", "", "Type of the new instances")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.MinOSVersion, "min-os-version", defaultMinOSVersion, "Minimum version of the OS")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.GluonImage, "gluon-image", defaultGluonImage, "Image containing gluon")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.RebootStrategy, "reboot-strategy", defaultRebootStrategy, "CoreOS reboot strategy")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.PrivateRegistryUrl, "private-registry-url", defaultPrivateRegistryUrl(), "URL of private docker registry")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.PrivateRegistryUserName, "private-registry-username", defaultPrivateRegistryUserName(), "Username for private registry")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.PrivateRegistryPassword, "private-registry-password", defaultPrivateRegistryPassword(), "Password for private registry")
	cmdCreateInstance.Flags().StringSliceVar(&createInstanceFlags.SSHKeyNames, "ssh-key", defaultSshKeys(), "Names of SSH keys to add to instance")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.SSHKeyGithubAccount, "ssh-key-github-account", defaultSshKeyGithubAccount(), "Github account name used to fetch SSH keys (to add to instances)")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.EtcdProxy, "etcd-proxy", false, "If set, the new instance will be an ETCD proxy")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleCore, "role-core", false, "If set, the new instance will get `core=true` metadata")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleLoadBalancer, "role-lb", false, "If set, the new instance will get `lb=true` metadata and register with cluster name in DNS")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleVault, "role-vault", false, "If set, the new instance will get `vault=true` metadata")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleWorker, "role-worker", false, "If set, the new instance will get `worker=true` metadata")
	cmdCreateInstance.Flags().IntVar(&createInstanceFlags.InstanceIndex, "index", 0, "Used to create `odd=true` or `even=true` metadata")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.TincCIDR, "tinc-cidr", "", "CIDR of the TINC network in this cluster")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.TincIpv4, "tinc-ipv4", "", "IPv4 address of the new instance inside the TINC network")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RegisterInstance, "register-instance", defaultRegisterInstance(), "If set, the instance will be registered with its instance name in DNS")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.HttpProxy, "http-proxy", "", "Address of HTTP proxy to use on the instance")
	cmdInstance.AddCommand(cmdCreateInstance)
}

func createInstance(cmd *cobra.Command, args []string) {
	createInstanceFlags.VaultAddress = vaultCfg.VaultAddr
	createInstanceFlags.VaultCertificatePath = vaultCfg.VaultCACert
	createInstanceFlags.VaultServerKeyPath = vaultCfg.VaultCAKey
	createInstanceFlags.VaultServerKeyCommand = vaultCfg.VaultCAKeyCommand

	requireProfile := true
	loadArgumentsFromCluster(cmd.Flags(), requireProfile)
	clusterInfoFromArgs(&createInstanceFlags.ClusterInfo, args)

	provider := newProvider()
	createInstanceFlags = provider.CreateInstanceDefaults(createInstanceFlags)
	createInstanceFlags.SetupNames("", createInstanceFlags.Name, createInstanceFlags.Domain)

	// Validate
	validateVault := false
	validateWeave := false
	if err := createInstanceFlags.Validate(validateVault, validateWeave); err != nil {
		Exitf("Create failed: %s\n", err.Error())
	}

	// See if there are already instances for the given cluster
	instances, err := provider.GetInstances(createInstanceFlags.ClusterInfo)
	if err != nil {
		Exitf("Failed to query existing instances: %v\n", err)
	}
	if len(instances) == 0 {
		Exitf("Cluster %s.%s does not exist.\n", createInstanceFlags.Name, createInstanceFlags.Domain)
	}

	// Fetch various variables from existing cluster
	g := errgroup.Group{}

	// Fetch cluster ID
	g.Go(func() error {
		clusterID, err := instances.GetClusterID(log)
		if err != nil {
			Exitf("Failed to get cluster-id: %v\n", err)
		}
		createInstanceFlags.ClusterInfo.ID = clusterID
		return nil
	})

	// Fetch vault address
	g.Go(func() error {
		vaultAddr, err := instances.GetVaultAddr(log)
		if err != nil {
			Exitf("Failed to get vault-addr: %v\n", err)
		}
		createInstanceFlags.VaultAddress = vaultAddr
		return nil
	})

	// Fetch vault CA certificate
	g.Go(func() error {
		vaultCACert, err := instances.GetVaultCrt(log)
		if err != nil {
			Exitf("Failed to get vault-cacert: %v\n", err)
		}
		createInstanceFlags.SetVaultCertificate(vaultCACert)
		return nil
	})

	// Fetch gluon.env
	g.Go(func() error {
		gluonEnv, err := instances.GetGluonEnv(log)
		if err != nil {
			Exitf("Failed to get gluon.env: %v\n", err)
		}
		createInstanceFlags.GluonEnv = gluonEnv
		return nil
	})

	// Fetch weave.env
	g.Go(func() error {
		weaveEnv, err := instances.GetWeaveEnv(log)
		if err != nil {
			Exitf("Failed to get weave.env: %v\n", err)
		}
		createInstanceFlags.WeaveEnv = weaveEnv
		return nil
	})

	// Fetch weave-seed
	g.Go(func() error {
		weaveSeed, err := instances.GetWeaveSeed(log)
		if err != nil {
			Exitf("Failed to get weave-seed: %v\n", err)
		}
		createInstanceFlags.WeaveSeed = weaveSeed
		return nil
	})

	// Wait for all fetch operations to complete
	if err := g.Wait(); err != nil {
		Exitf("Failed to get data from existing cluster: %v\n", err)
	}

	// Setup instance index
	if createInstanceFlags.InstanceIndex == 0 {
		createInstanceFlags.InstanceIndex = len(instances) + 1
	}

	// Check tinc IP (if any)
	if createInstanceFlags.TincIpv4 != "" {
		for _, i := range instances {
			if i.ClusterIP == createInstanceFlags.TincIpv4 {
				Exitf("Duplicate cluster IP: %s\n", createInstanceFlags.TincIpv4)
			}
		}
	}

	// Now validate everything
	validateVault = true
	validateWeave = true
	if err := createInstanceFlags.Validate(validateVault, validateWeave); err != nil {
		Exitf("Create failed: %s\n", err.Error())
	}

	// Create
	log.Infof("Creating new instance on %s.%s", createInstanceFlags.Name, createInstanceFlags.Domain)
	instance, err := provider.CreateInstance(log, createInstanceFlags, newDnsProvider())
	if err != nil {
		Exitf("Failed to create new instance: %v\n", err)
	}

	// Get the id of the new machine
	machineID, err := instance.GetMachineID(log)
	if err != nil {
		Exitf("Failed to get machine ID: %v\n", err)
	}

	// Add new instance to ETCD (if not a proxy)
	if !createInstanceFlags.EtcdProxy {
		if err := instances.AddEtcdMember(log, machineID, instance.ClusterIP); err != nil {
			Exitf("Failed to add new instance to etcd: %v\n", err)
		}
	}

	// Add new instance to vault cluster
	if err := newVaultProvider().AddMachine(createInstanceFlags.ClusterInfo.ID, machineID); err != nil {
		log.Warningf("Failed to add machine to vault: %#v", err)
	}

	// Add new instance to list
	instances = append(instances, instance)

	// Load cluster-members data
	isEtcdProxy := func(i providers.ClusterInstance) (bool, error) {
		if i.ClusterIP == instance.ClusterIP {
			return createInstanceFlags.EtcdProxy, nil
		}
		result, err := i.IsEtcdProxy(log)
		return result, maskAny(err)
	}
	clusterMembers, err := instances.AsClusterMemberList(log, isEtcdProxy)
	if err != nil {
		Exitf("Failed to convert instance list to member list: %v\n", err)
	}

	// Perform initial setup on new instance
	iso := providers.InitialSetupOptions{
		ClusterMembers:   clusterMembers,
		FleetMetadata:    createInstanceFlags.CreateFleetMetadata(createInstanceFlags.InstanceIndex),
		EtcdClusterState: "existing",
	}
	if err := instance.InitialSetup(log, createInstanceFlags, iso, provider); err != nil {
		Exitf("Failed to perform initial instance setup: %v\n", err)
	}

	// Update existing members
	if err := providers.UpdateClusterMembers(log, createInstanceFlags.ClusterInfo, false, isEtcdProxy, provider); err != nil {
		Exitf("Failed to update cluster members: %v\n", err)
	}

	// Reboot new instance
	if err := provider.RebootInstance(instance); err != nil {
		Exitf("Failed to reboot new instance: %v\n", err)
	}

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

package main

import (
	"github.com/spf13/cobra"
	"golang.org/x/sync/errgroup"

	"github.com/pulcy/quark/providers"
)

var (
	cmdCreateInstance = &cobra.Command{
		Use: "create",
		Run: createInstance,
		Example: `Create a new instance with role 'worker' in 'mycluster'.
	./quark instance create -c worker@mycluster

Create a new instance with a specific cluster (tinc) IP.
	./quark instance create -c worker@mycluster --tinc-ipv4=192.168.33.11
`,
	}

	createInstanceFlags providers.CreateInstanceOptions
)

func init() {
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.Domain, "domain", defaultDomain(), "Cluster domain")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.Name, "name", "", "Cluster name")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.ImageID, "image", "", "OS image to run on new instances")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.RegionID, "region", "", "Region to create the instances in")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.TypeID, "type", "", "Type of the new instances")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.MinOSVersion, "min-os-version", defaultMinOSVersion, "Minimum version of the OS")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.GluonImage, "gluon-image", defaultGluonImage, "Image containing gluon")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.RebootStrategy, "reboot-strategy", defaultRebootStrategy, "CoreOS reboot strategy")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.PrivateRegistryUrl, "private-registry-url", defaultPrivateRegistryUrl(), "URL of private docker registry")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.PrivateRegistryUserName, "private-registry-username", defaultPrivateRegistryUserName(), "Username for private registry")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.PrivateRegistryPassword, "private-registry-password", defaultPrivateRegistryPassword(), "Password for private registry")
	cmdCreateInstance.Flags().StringSliceVar(&createInstanceFlags.SSHKeyNames, "ssh-key", defaultSshKeys(), "Names of SSH keys to add to instance")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.SSHKeyGithubAccount, "ssh-key-github-account", defaultSshKeyGithubAccount(), "Github account name used to fetch SSH keys (to add to instances)")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.EtcdProxy, "etcd-proxy", false, "If set, the new instance will be an ETCD proxy")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleCore, "role-core", false, "If set, the new instance will get `core=true` metadata")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleLoadBalancer, "role-lb", false, "If set, the new instance will get `lb=true` metadata and register with cluster name in DNS")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleVault, "role-vault", false, "If set, the new instance will get `vault=true` metadata")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RoleWorker, "role-worker", false, "If set, the new instance will get `worker=true` metadata")
	cmdCreateInstance.Flags().IntVar(&createInstanceFlags.InstanceIndex, "index", 0, "Used to create `odd=true` or `even=true` metadata")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.TincCIDR, "tinc-cidr", "", "CIDR of the TINC network in this cluster")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.TincIpv4, "tinc-ipv4", "", "IPv4 address of the new instance inside the TINC network")
	cmdCreateInstance.Flags().BoolVar(&createInstanceFlags.RegisterInstance, "register-instance", defaultRegisterInstance(), "If set, the instance will be registered with its instance name in DNS")
	cmdCreateInstance.Flags().StringVar(&createInstanceFlags.HttpProxy, "http-proxy", "", "Address of HTTP proxy to use on the instance")
	cmdInstance.AddCommand(cmdCreateInstance)
}

func createInstance(cmd *cobra.Command, args []string) {
	createInstanceFlags.VaultAddress = vaultCfg.VaultAddr
	createInstanceFlags.VaultCertificatePath = vaultCfg.VaultCACert
	createInstanceFlags.VaultServerKeyPath = vaultCfg.VaultCAKey
	createInstanceFlags.VaultServerKeyCommand = vaultCfg.VaultCAKeyCommand

	requireProfile := true
	loadArgumentsFromCluster(cmd.Flags(), requireProfile)
	clusterInfoFromArgs(&createInstanceFlags.ClusterInfo, args)

	provider := newProvider()
	createInstanceFlags = provider.CreateInstanceDefaults(createInstanceFlags)
	createInstanceFlags.SetupNames("", createInstanceFlags.Name, createInstanceFlags.Domain)

	// Validate
	validateVault := false
	validateWeave := false
	if err := createInstanceFlags.Validate(validateVault, validateWeave); err != nil {
		Exitf("Create failed: %s\n", err.Error())
	}

	// See if there are already instances for the given cluster
	instances, err := provider.GetInstances(createInstanceFlags.ClusterInfo)
	if err != nil {
		Exitf("Failed to query existing instances: %v\n", err)
	}
	if len(instances) == 0 {
		Exitf("Cluster %s.%s does not exist.\n", createInstanceFlags.Name, createInstanceFlags.Domain)
	}

	// Fetch various variables from existing cluster
	g := errgroup.Group{}

	// Fetch cluster ID
	g.Go(func() error {
		clusterID, err := instances.GetClusterID(log)
		if err != nil {
			Exitf("Failed to get cluster-id: %v\n", err)
		}
		createInstanceFlags.ClusterInfo.ID = clusterID
		return nil
	})

	// Fetch vault address
	g.Go(func() error {
		vaultAddr, err := instances.GetVaultAddr(log)
		if err != nil {
			Exitf("Failed to get vault-addr: %v\n", err)
		}
		createInstanceFlags.VaultAddress = vaultAddr
		return nil
	})

	// Fetch vault CA certificate
	g.Go(func() error {
		vaultCACert, err := instances.GetVaultCrt(log)
		if err != nil {
			Exitf("Failed to get vault-cacert: %v\n", err)
		}
		createInstanceFlags.SetVaultCertificate(vaultCACert)
		return nil
	})

	// Fetch gluon.env
	g.Go(func() error {
		gluonEnv, err := instances.GetGluonEnv(log)
		if err != nil {
			Exitf("Failed to get gluon.env: %v\n", err)
		}
		createInstanceFlags.GluonEnv = gluonEnv
		return nil
	})

	// Fetch weave.env
	g.Go(func() error {
		weaveEnv, err := instances.GetWeaveEnv(log)
		if err != nil {
			Exitf("Failed to get weave.env: %v\n", err)
		}
		createInstanceFlags.WeaveEnv = weaveEnv
		return nil
	})

	// Fetch weave-seed
	g.Go(func() error {
		weaveSeed, err := instances.GetWeaveSeed(log)
		if err != nil {
			Exitf("Failed to get weave-seed: %v\n", err)
		}
		createInstanceFlags.WeaveSeed = weaveSeed
		return nil
	})

	// Wait for all fetch operations to complete
	if err := g.Wait(); err != nil {
		Exitf("Failed to get data from existing cluster: %v\n", err)
	}

	// Setup instance index
	if createInstanceFlags.InstanceIndex == 0 {
		createInstanceFlags.InstanceIndex = len(instances) + 1
	}

	// Check tinc IP (if any)
	if createInstanceFlags.TincIpv4 != "" {
		for _, i := range instances {
			if i.ClusterIP == createInstanceFlags.TincIpv4 {
				Exitf("Duplicate cluster IP: %s\n", createInstanceFlags.TincIpv4)
			}
		}
	}

	// Now validate everything
	validateVault = true
	validateWeave = true
	if err := createInstanceFlags.Validate(validateVault, validateWeave); err != nil {
		Exitf("Create failed: %s\n", err.Error())
	}

	// Create
	log.Infof("Creating new instance on %s.%s", createInstanceFlags.Name, createInstanceFlags.Domain)
	instance, err := provider.CreateInstance(log, createInstanceFlags, newDnsProvider())
	if err != nil {
		Exitf("Failed to create new instance: %v\n", err)
	}

	// Get the id of the new machine
	machineID, err := instance.GetMachineID(log)
	if err != nil {
		Exitf("Failed to get machine ID: %v\n", err)
	}

	// Add new instance to ETCD (if not a proxy)
	if !createInstanceFlags.EtcdProxy {
		if err := instances.AddEtcdMember(log, machineID, instance.ClusterIP); err != nil {
			Exitf("Failed to add new instance to etcd: %v\n", err)
		}
	}

	// Add new instance to vault cluster
	if err := newVaultProvider().AddMachine(createInstanceFlags.ClusterInfo.ID, machineID); err != nil {
		log.Warningf("Failed to add machine to vault: %#v", err)
	}

	// Add new instance to list
	instances = append(instances, instance)

	// Load cluster-members data
	isEtcdProxy := func(i providers.ClusterInstance) (bool, error) {
		if i.ClusterIP == instance.ClusterIP {
			return createInstanceFlags.EtcdProxy, nil
		}
		result, err := i.IsEtcdProxy(log)
		return result, maskAny(err)
	}
	clusterMembers, err := instances.AsClusterMemberList(log, isEtcdProxy)
	if err != nil {
		Exitf("Failed to convert instance list to member list: %v\n", err)
	}

	// Perform initial setup on new instance
	iso := providers.InitialSetupOptions{
		ClusterMembers:   clusterMembers,
		FleetMetadata:    createInstanceFlags.CreateFleetMetadata(createInstanceFlags.InstanceIndex),
		EtcdClusterState: "existing",
	}
	if err := instance.InitialSetup(log, createInstanceFlags, iso, provider); err != nil {
		Exitf("Failed to perform initial instance setup: %v\n", err)
	}

	// Update existing members
	if err := providers.UpdateClusterMembers(log, createInstanceFlags.ClusterInfo, false, isEtcdProxy, provider); err != nil {
		Exitf("Failed to update cluster members: %v\n", err)
	}

	// Reboot new instance
	if err := provider.RebootInstance(instance); err != nil {
		Exitf("Failed to reboot new instance: %v\n", err)
	}

	Infof("Instance created\n")
}
<|endoftext|>


<commit_before>package integration

import (
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"github.com/robxu9/kahinah/models"
	"github.com/robxu9/kahinah/util"
	"io/ioutil"
	"log"
	"menteslibres.net/gosexy/dig"
	"menteslibres.net/gosexy/to"
	"net/http"
	"strings"
	"time"
)

const (
	ABF_URL = "https://abf.rosalinux.ru/api/v1"
)

var (
	user      = beego.AppConfig.String("abf_user")
	pass      = beego.AppConfig.String("abf_pass")
	platforms util.Set
	client    = &http.Client{}
)

func init() {
	platforms = util.NewSet()
	for _, v := range strings.Split(beego.AppConfig.String("abf_platforms"), ";") {
		platforms.Add(v)
	}
}

type ABF byte

func (a ABF) Ping() error {
	err := a.pingBuildCompleted()
	err2 := a.pingTestingBuilds()

	// FUTURE TODO: ping published & rejected builds to ensure consistency

	if err != nil && err2 != nil {
		return fmt.Errorf("abf: two errors: %s | %s", err, err2)
	} else if err != nil {
		return err
	} else if err2 != nil {
		return err2
	}

	return nil
}

func (a ABF) pingBuildCompleted() error {
	// regular usage: use 0 (Build has been completed)
	// below: use 12000 ([testing] build has been published)
	// FIXME - remove hardcoded openmandriva2013.0 filter (but find alternative, we need said filter)
	req, err := http.NewRequest("GET", ABF_URL+"/build_lists.json?per_page=100&filter[status]=0&filter[ownership]=index&filter[platform_id]=668", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	var result map[string]interface{}

	err = json.Unmarshal(body, &result)
	if err != nil {
		return err
	}

	var lists []interface{}

	err = dig.Get(&result, &lists, "build_lists")
	if err != nil {
		return err
	}

	o := orm.NewOrm()

	for _, v := range lists {
		asserted := v.(map[string]interface{})
		id := dig.Uint64(&asserted, "id")

		var list models.BuildList
		err := o.QueryTable(new(models.BuildList)).Filter("ListId", id).One(&list)
		if err != nil {
			list, err = a.getBuildList(id)
			if err != nil {
				log.Printf("abf: Error retrieving build list %s: %s\n", id, err)
			}

			if !platforms.Contains(list.Platform) {
				// ignore
				continue
			}

			// Now send it to testing
			go a.sendToTesting(id)

			_, err = o.Insert(&list)
			if err != nil {
				log.Printf("abf: Error saving build list %s: %s\n", id, err)
			}
		}
	}

	return nil
}

func (a ABF) pingTestingBuilds() error {
	// FIXME - remove hardcoded openmandriva2013.0 filter (but find alternative, we need said filter)
	req, err := http.NewRequest("GET", ABF_URL+"/build_lists.json?per_page=100&filter[status]=12000&filter[ownership]=index&filter[platform_id]=668", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	var result map[string]interface{}

	err = json.Unmarshal(body, &result)
	if err != nil {
		return err
	}

	var lists []interface{}

	err = dig.Get(&result, &lists, "build_lists")
	if err != nil {
		return err
	}

	o := orm.NewOrm()

	for _, v := range lists {
		asserted := v.(map[string]interface{})
		id := dig.Uint64(&asserted, "id")

		var list models.BuildList
		err := o.QueryTable(new(models.BuildList)).Filter("ListId", id).One(&list)
		if err != nil {
			list, err = a.getBuildList(id)
			if err != nil {
				log.Printf("abf: Error retrieving build list %s: %s\n", id, err)
			}

			if !platforms.Contains(list.Platform) {
				// ignore
				continue
			}

			_, err = o.Insert(&list)
			if err != nil {
				log.Printf("abf: Error saving build list %s: %s\n", id, err)
			}
		}
	}

	return nil
}

func (a ABF) PingParams(m map[string]string) error {
	return fmt.Errorf("abf: PingParams not supported yet.")
}

func (a ABF) Publish(id uint64) error {
	req, err := http.NewRequest("PUT", ABF_URL+"/build_lists/"+to.String(id)+"/publish.json", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	return nil
}

func (a ABF) Reject(id uint64) error {
	req, err := http.NewRequest("PUT", ABF_URL+"/build_lists/"+to.String(id)+"/reject_publish.json", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	return nil
}

func (a ABF) sendToTesting(id uint64) error {
	req, err := http.NewRequest("PUT", ABF_URL+"/build_lists/"+to.String(id)+"/publish_into_testing.json", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	return nil
}

func (a ABF) getBuildList(id uint64) (models.BuildList, error) {
	req, err := http.NewRequest("GET", ABF_URL+"/build_lists/"+to.String(id)+".json", nil)
	if err != nil {
		return models.BuildList{}, err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return models.BuildList{}, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return models.BuildList{}, err
	}

	var result map[string]interface{}

	err = json.Unmarshal(body, &result)
	if err != nil {
		return models.BuildList{}, err
	}

	var list map[string]interface{}

	dig.Get(&result, &list, "build_list")

	pkgs := make([]interface{}, 0)
	dig.Get(&list, &pkgs, "packages")

	pkg := ""

	pkgrep := func(m map[string]interface{}) string {
		res := dig.String(&m, "name") + " "
		if dig.String(&m, "epoch") != "" {
			res += dig.String(&m, "epoch")
			res += ":"
		}
		res += dig.String(&m, "version") + "-"
		res += dig.String(&m, "release")
		return res
	}

	for _, v := range pkgs {
		asserted := v.(map[string]interface{})
		if dig.String(&asserted, "type") == "source" {
			continue // no source packages
		}
		if strings.HasSuffix(dig.String(&asserted, "name"), "-debuginfo") {
			continue // no debuginfo packages
		}
		if pkg == "" {
			pkg = pkgrep(asserted)
		} else {
			pkg = pkg + ";" + pkgrep(asserted)
		}
	}

	changelog := ""

	logs := make([]interface{}, 0)
	dig.Get(&list, &logs, "logs")

	for _, v := range logs {
		asserted := v.(map[string]interface{})
		if dig.String(&asserted, "file_name") == "changelog.log" {
			changelog = dig.String(&asserted, "url")
			break
		}
	}

	bl := models.BuildList{ListId: dig.Uint64(&list, "id"),
		//Platform:     dig.String(&list, "build_for_platform", "name"),
		Platform:      dig.String(&list, "save_to_repository", "platform", "name"),
		Repo:          dig.String(&list, "save_to_repository", "name"),
		Architecture:  dig.String(&list, "arch", "name"),
		Name:          dig.String(&list, "project", "name"),
		Submitter:     dig.String(&list, "user", "name"),
		Type:          dig.String(&list, "update_type"),
		Status:        models.STATUS_TESTING,
		Url:           "https://abf.rosalinux.ru/build_lists/" + to.String(dig.Uint64(&list, "id")),
		Changelog:     changelog, // url
		PublishHandle: "abf",
		RejectHandle:  "abf",
		Packages:      pkg,
		BuildDate:     time.Unix(dig.Int64(&list, "updated_at"), 0)}

	return bl, nil

}
<commit_msg>use abf.io instead of abf.rosalinux.ru<commit_after>package integration

import (
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"github.com/robxu9/kahinah/models"
	"github.com/robxu9/kahinah/util"
	"io/ioutil"
	"log"
	"menteslibres.net/gosexy/dig"
	"menteslibres.net/gosexy/to"
	"net/http"
	"strings"
	"time"
)

const (
	ABF_URL = "https://abf.io/api/v1"
)

var (
	user      = beego.AppConfig.String("abf_user")
	pass      = beego.AppConfig.String("abf_pass")
	platforms util.Set
	client    = &http.Client{}
)

func init() {
	platforms = util.NewSet()
	for _, v := range strings.Split(beego.AppConfig.String("abf_platforms"), ";") {
		platforms.Add(v)
	}
}

type ABF byte

func (a ABF) Ping() error {
	err := a.pingBuildCompleted()
	err2 := a.pingTestingBuilds()

	// FUTURE TODO: ping published & rejected builds to ensure consistency

	if err != nil && err2 != nil {
		return fmt.Errorf("abf: two errors: %s | %s", err, err2)
	} else if err != nil {
		return err
	} else if err2 != nil {
		return err2
	}

	return nil
}

func (a ABF) pingBuildCompleted() error {
	// regular usage: use 0 (Build has been completed)
	// below: use 12000 ([testing] build has been published)
	// FIXME - remove hardcoded openmandriva2013.0 filter (but find alternative, we need said filter)
	req, err := http.NewRequest("GET", ABF_URL+"/build_lists.json?per_page=100&filter[status]=0&filter[ownership]=index&filter[platform_id]=668", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	var result map[string]interface{}

	err = json.Unmarshal(body, &result)
	if err != nil {
		return err
	}

	var lists []interface{}

	err = dig.Get(&result, &lists, "build_lists")
	if err != nil {
		return err
	}

	o := orm.NewOrm()

	for _, v := range lists {
		asserted := v.(map[string]interface{})
		id := dig.Uint64(&asserted, "id")

		var list models.BuildList
		err := o.QueryTable(new(models.BuildList)).Filter("ListId", id).One(&list)
		if err != nil {
			list, err = a.getBuildList(id)
			if err != nil {
				log.Printf("abf: Error retrieving build list %s: %s\n", id, err)
			}

			if !platforms.Contains(list.Platform) {
				// ignore
				continue
			}

			// Now send it to testing
			go a.sendToTesting(id)

			_, err = o.Insert(&list)
			if err != nil {
				log.Printf("abf: Error saving build list %s: %s\n", id, err)
			}
		}
	}

	return nil
}

func (a ABF) pingTestingBuilds() error {
	// FIXME - remove hardcoded openmandriva2013.0 filter (but find alternative, we need said filter)
	req, err := http.NewRequest("GET", ABF_URL+"/build_lists.json?per_page=100&filter[status]=12000&filter[ownership]=index&filter[platform_id]=668", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	var result map[string]interface{}

	err = json.Unmarshal(body, &result)
	if err != nil {
		return err
	}

	var lists []interface{}

	err = dig.Get(&result, &lists, "build_lists")
	if err != nil {
		return err
	}

	o := orm.NewOrm()

	for _, v := range lists {
		asserted := v.(map[string]interface{})
		id := dig.Uint64(&asserted, "id")

		var list models.BuildList
		err := o.QueryTable(new(models.BuildList)).Filter("ListId", id).One(&list)
		if err != nil {
			list, err = a.getBuildList(id)
			if err != nil {
				log.Printf("abf: Error retrieving build list %s: %s\n", id, err)
			}

			if !platforms.Contains(list.Platform) {
				// ignore
				continue
			}

			_, err = o.Insert(&list)
			if err != nil {
				log.Printf("abf: Error saving build list %s: %s\n", id, err)
			}
		}
	}

	return nil
}

func (a ABF) PingParams(m map[string]string) error {
	return fmt.Errorf("abf: PingParams not supported yet.")
}

func (a ABF) Publish(id uint64) error {
	req, err := http.NewRequest("PUT", ABF_URL+"/build_lists/"+to.String(id)+"/publish.json", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	return nil
}

func (a ABF) Reject(id uint64) error {
	req, err := http.NewRequest("PUT", ABF_URL+"/build_lists/"+to.String(id)+"/reject_publish.json", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	return nil
}

func (a ABF) sendToTesting(id uint64) error {
	req, err := http.NewRequest("PUT", ABF_URL+"/build_lists/"+to.String(id)+"/publish_into_testing.json", nil)
	if err != nil {
		return err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	return nil
}

func (a ABF) getBuildList(id uint64) (models.BuildList, error) {
	req, err := http.NewRequest("GET", ABF_URL+"/build_lists/"+to.String(id)+".json", nil)
	if err != nil {
		return models.BuildList{}, err
	}

	req.SetBasicAuth(user, pass)

	resp, err := client.Do(req)
	if err != nil {
		return models.BuildList{}, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return models.BuildList{}, err
	}

	var result map[string]interface{}

	err = json.Unmarshal(body, &result)
	if err != nil {
		return models.BuildList{}, err
	}

	var list map[string]interface{}

	dig.Get(&result, &list, "build_list")

	pkgs := make([]interface{}, 0)
	dig.Get(&list, &pkgs, "packages")

	pkg := ""

	pkgrep := func(m map[string]interface{}) string {
		res := dig.String(&m, "name") + " "
		if dig.String(&m, "epoch") != "" {
			res += dig.String(&m, "epoch")
			res += ":"
		}
		res += dig.String(&m, "version") + "-"
		res += dig.String(&m, "release")
		return res
	}

	for _, v := range pkgs {
		asserted := v.(map[string]interface{})
		if dig.String(&asserted, "type") == "source" {
			continue // no source packages
		}
		if strings.HasSuffix(dig.String(&asserted, "name"), "-debuginfo") {
			continue // no debuginfo packages
		}
		if pkg == "" {
			pkg = pkgrep(asserted)
		} else {
			pkg = pkg + ";" + pkgrep(asserted)
		}
	}

	changelog := ""

	logs := make([]interface{}, 0)
	dig.Get(&list, &logs, "logs")

	for _, v := range logs {
		asserted := v.(map[string]interface{})
		if dig.String(&asserted, "file_name") == "changelog.log" {
			changelog = dig.String(&asserted, "url")
			break
		}
	}

	bl := models.BuildList{ListId: dig.Uint64(&list, "id"),
		//Platform:     dig.String(&list, "build_for_platform", "name"),
		Platform:      dig.String(&list, "save_to_repository", "platform", "name"),
		Repo:          dig.String(&list, "save_to_repository", "name"),
		Architecture:  dig.String(&list, "arch", "name"),
		Name:          dig.String(&list, "project", "name"),
		Submitter:     dig.String(&list, "user", "name"),
		Type:          dig.String(&list, "update_type"),
		Status:        models.STATUS_TESTING,
		Url:           "https://abf.io/build_lists/" + to.String(dig.Uint64(&list, "id")),
		Changelog:     changelog, // url
		PublishHandle: "abf",
		RejectHandle:  "abf",
		Packages:      pkg,
		BuildDate:     time.Unix(dig.Int64(&list, "updated_at"), 0)}

	return bl, nil

}
<|endoftext|>


<commit_before>/*
Copyright 2018 Google LLC

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 integration

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"
	"time"

	integration_util "github.com/grafeas/kritis/pkg/kritis/integration_util"
	"github.com/grafeas/kritis/pkg/kritis/testutil"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/wait"
)

const (
	testAttesationAuthority = `apiVersion: kritis.grafeas.io/v1beta1
kind: AttestationAuthority
metadata:
  name: test-attestor
spec:
  noteReference: v1alpha1/projects/krits-int-test
  privateKeySecretName: %s
  publicKeyData: %s`
)

// Secret name for test-attestor
var aaSecret = "test-attestor"

// CRDs is a map of CRD type to names of the expected CRDs to create.
var crdNames = map[string]string{
	"imagesecuritypolicies.kritis.grafeas.io": "my-isp",
}

var crdExamples = []string{
	"image-security-policy-example.yaml",
}
var templateFile = "attestation-authority-example.yaml.template"
var templateFileSuffix = ".template"

func createAttestationAuthority(t *testing.T, ns string) {
	t.Helper()
	// Generate a key value pair
	pubKey, privKey := testutil.CreateKeyPair(t, aaSecret)
	// get the base encoded value for public key.
	pubKeyEnc := base64.StdEncoding.EncodeToString([]byte(pubKey))

	// create a tmp dir for keys
	d, err := ioutil.TempDir("", "_keys")
	if err != nil {
		t.Fatalf("unexpected error %s", err)
	}
	defer os.RemoveAll(d)

	// create file with contents in dir
	pubFile := createFileWithContents(t, d, pubKey)

	privFile := createFileWithContents(t, d, privKey)

	// Finally create a kubernetes secret.
	cmd := exec.Command("kubectl", "create", "secret", "generic", aaSecret,
		fmt.Sprintf("--from-file=public=%s", pubFile),
		fmt.Sprintf("--from-file=private=%s", privFile),
		"-n", ns)
	if _, err := integration_util.RunCmdOut(cmd); err != nil {
		t.Fatalf("unexpected error %s", err)
	}

	// Create the Attestation authority
	createAA(t, ns, pubKeyEnc)
}

func createCRDExamples(t *testing.T, ns *v1.Namespace) {
	t.Helper()
	createAttestationAuthority(t, ns.Name)
	for _, crd := range crdExamples {
		crdCmd := exec.Command("kubectl", "create", "-f", crd, "-n", ns.Name)
		crdCmd.Dir = "../artifacts/integration-examples"
		if _, err := integration_util.RunCmdOut(crdCmd); err != nil {
			t.Fatalf("testing error: %v", err)
		}
	}
}

func waitForCRDExamples(t *testing.T, ns *v1.Namespace) {
	t.Helper()
	for crd, name := range crdNames {
		err := wait.PollImmediate(500*time.Millisecond, time.Minute*2, func() (bool, error) {
			crdCmd := exec.Command("kubectl", "get", crd, name, "-n", ns.Name)
			_, err := integration_util.RunCmdOut(crdCmd)
			return (err == nil), err
		})
		if err != nil {
			t.Fatalf("timeout waiting for crds: %v", err)
		}
	}
}

func createFileWithContents(t *testing.T, d string, c string) string {
	t.Helper()
	file, err := ioutil.TempFile(d, "gpg")
	if err != nil {
		t.Fatalf("testing error: %v", err)
	}
	if _, err := file.WriteString(c); err != nil {
		t.Fatalf("testing error: %v", err)
	}
	return file.Name()
}

func createAA(t *testing.T, ns string, pubkey string) {
	t.Helper()
	cmd := exec.Command("kubectl", "apply", "-f", "-")
	cmd.Stdin = bytes.NewReader([]byte(fmt.Sprintf(testAttesationAuthority, aaSecret, pubkey)))
	if _, err := integration_util.RunCmdOut(cmd); err != nil {
		t.Fatalf("testing error: %v", err)
	}
}
<commit_msg>fix lint<commit_after>/*
Copyright 2018 Google LLC

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 integration

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"
	"time"

	integration_util "github.com/grafeas/kritis/pkg/kritis/integration_util"
	"github.com/grafeas/kritis/pkg/kritis/testutil"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/wait"
)

const (
	testAttesationAuthority = `apiVersion: kritis.grafeas.io/v1beta1
kind: AttestationAuthority
metadata:
  name: test-attestor
spec:
  noteReference: v1alpha1/projects/krits-int-test
  privateKeySecretName: %s
  publicKeyData: %s`
)

// Secret name for test-attestor
var aaSecret = "test-attestor"

// CRDs is a map of CRD type to names of the expected CRDs to create.
var crdNames = map[string]string{
	"imagesecuritypolicies.kritis.grafeas.io": "my-isp",
}

var crdExamples = []string{
	"image-security-policy-example.yaml",
}

func createAttestationAuthority(t *testing.T, ns string) {
	t.Helper()
	// Generate a key value pair
	pubKey, privKey := testutil.CreateKeyPair(t, aaSecret)
	// get the base encoded value for public key.
	pubKeyEnc := base64.StdEncoding.EncodeToString([]byte(pubKey))

	// create a tmp dir for keys
	d, err := ioutil.TempDir("", "_keys")
	if err != nil {
		t.Fatalf("unexpected error %s", err)
	}
	defer os.RemoveAll(d)

	// create file with contents in dir
	pubFile := createFileWithContents(t, d, pubKey)

	privFile := createFileWithContents(t, d, privKey)

	// Finally create a kubernetes secret.
	cmd := exec.Command("kubectl", "create", "secret", "generic", aaSecret,
		fmt.Sprintf("--from-file=public=%s", pubFile),
		fmt.Sprintf("--from-file=private=%s", privFile),
		"-n", ns)
	if _, err := integration_util.RunCmdOut(cmd); err != nil {
		t.Fatalf("unexpected error %s", err)
	}

	// Create the Attestation authority
	createAA(t, ns, pubKeyEnc)
}

func createCRDExamples(t *testing.T, ns *v1.Namespace) {
	t.Helper()
	createAttestationAuthority(t, ns.Name)
	for _, crd := range crdExamples {
		crdCmd := exec.Command("kubectl", "create", "-f", crd, "-n", ns.Name)
		crdCmd.Dir = "../artifacts/integration-examples"
		if _, err := integration_util.RunCmdOut(crdCmd); err != nil {
			t.Fatalf("testing error: %v", err)
		}
	}
}

func waitForCRDExamples(t *testing.T, ns *v1.Namespace) {
	t.Helper()
	for crd, name := range crdNames {
		err := wait.PollImmediate(500*time.Millisecond, time.Minute*2, func() (bool, error) {
			crdCmd := exec.Command("kubectl", "get", crd, name, "-n", ns.Name)
			_, err := integration_util.RunCmdOut(crdCmd)
			return (err == nil), err
		})
		if err != nil {
			t.Fatalf("timeout waiting for crds: %v", err)
		}
	}
}

func createFileWithContents(t *testing.T, d string, c string) string {
	t.Helper()
	file, err := ioutil.TempFile(d, "gpg")
	if err != nil {
		t.Fatalf("testing error: %v", err)
	}
	if _, err := file.WriteString(c); err != nil {
		t.Fatalf("testing error: %v", err)
	}
	return file.Name()
}

func createAA(t *testing.T, ns string, pubkey string) {
	t.Helper()
	cmd := exec.Command("kubectl", "apply", "-n", ns, "-f", "-")
	cmd.Stdin = bytes.NewReader([]byte(fmt.Sprintf(testAttesationAuthority, aaSecret, pubkey)))
	if _, err := integration_util.RunCmdOut(cmd); err != nil {
		t.Fatalf("testing error: %v", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 CNI 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 invoke

import (
	"fmt"
	"os"
	"strings"

	"github.com/containernetworking/cni/pkg/types"
)

func DelegateAdd(delegatePlugin string, netconf []byte) (types.Result, error) {
	if os.Getenv("CNI_COMMAND") != "ADD" {
		return nil, fmt.Errorf("CNI_COMMAND is not ADD")
	}

	paths := strings.Split(os.Getenv("CNI_PATH"), ":")

	pluginPath, err := FindInPath(delegatePlugin, paths)
	if err != nil {
		return nil, err
	}

	return ExecPluginWithResult(pluginPath, netconf, ArgsFromEnv())
}

func DelegateDel(delegatePlugin string, netconf []byte) error {
	if os.Getenv("CNI_COMMAND") != "DEL" {
		return fmt.Errorf("CNI_COMMAND is not DEL")
	}

	paths := strings.Split(os.Getenv("CNI_PATH"), ":")

	pluginPath, err := FindInPath(delegatePlugin, paths)
	if err != nil {
		return err
	}

	return ExecPluginWithoutResult(pluginPath, netconf, ArgsFromEnv())
}
<commit_msg>spec, libcni, pkg/invoke: Use OS-agnostic separator when parsing CNI_PATH<commit_after>// Copyright 2016 CNI 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 invoke

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/containernetworking/cni/pkg/types"
)

func DelegateAdd(delegatePlugin string, netconf []byte) (types.Result, error) {
	if os.Getenv("CNI_COMMAND") != "ADD" {
		return nil, fmt.Errorf("CNI_COMMAND is not ADD")
	}

	paths := filepath.SplitList(os.Getenv("CNI_PATH"))

	pluginPath, err := FindInPath(delegatePlugin, paths)
	if err != nil {
		return nil, err
	}

	return ExecPluginWithResult(pluginPath, netconf, ArgsFromEnv())
}

func DelegateDel(delegatePlugin string, netconf []byte) error {
	if os.Getenv("CNI_COMMAND") != "DEL" {
		return fmt.Errorf("CNI_COMMAND is not DEL")
	}

	paths := filepath.SplitList(os.Getenv("CNI_PATH"))

	pluginPath, err := FindInPath(delegatePlugin, paths)
	if err != nil {
		return err
	}

	return ExecPluginWithoutResult(pluginPath, netconf, ArgsFromEnv())
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 turbobytes
//
// This file is part of geoipdb, a library of GeoIP related helper functions
// for TurboBytes stack.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package iputils

import (
	"net"
)

func init() {
	// Initialize nonGlobalIPv*Nets
	nonGlobalIPv4Nets = make([]*net.IPNet, len(nonGlobalIPv4CIDRs))
	for i, cidr := range nonGlobalIPv4CIDRs {
		_, inet, err := net.ParseCIDR(cidr)
		if err != nil {
			panic(err)
		}
		nonGlobalIPv4Nets[i] = inet
	}
	nonGlobalIPv6Nets = make([]*net.IPNet, len(nonGlobalIPv6CIDRs))
	for i, cidr := range nonGlobalIPv6CIDRs {
		_, inet, err := net.ParseCIDR(cidr)
		if err != nil {
			panic(err)
		}
		nonGlobalIPv6Nets[i] = inet
	}
}

var (
	nonGlobalIPv4Nets []*net.IPNet
	nonGlobalIPv6Nets []*net.IPNet
)

// nonGlobalIPv4CIDRs contains IANA IPv4 Special-Purpose Address Registry,
// where 'Global' flag is false.
//
// http://www.iana.org/assignments/iana-ipv4-special-registry/
var nonGlobalIPv4CIDRs = []string{
	"127.0.0.0/8",        // Loopback, RFC1122
	"192.168.0.0/16",     // Private-Use, RFC1918
	"10.0.0.0/8",         // Private-Use, RFC1918
	"172.16.0.0/12",      // Private-Use, RFC1918
	"0.0.0.0/8",          // "This host on this network", RFC1122 section 3.2.1.3
	"100.64.0.0/10",      // Shared Address Space, RFC6598
	"169.254.0.0/16",     // Link Local, RFC3927
	"192.0.0.0/24",       // IETF Protocol Assignments, RFC6890
	"192.0.2.0/24",       // Documentation (TEST-NET-1), RFC5737
	"198.18.0.0/15",      // Benchmarking, RFC2544
	"198.51.100.0/24",    // Documentation (TEST-NET-2), RFC5737
	"203.0.113.0/24",     // Documentation (TEST-NET-3), RFC5737
	"240.0.0.0/4",        // Reserved, RFC1112
	"255.255.255.255/32", // Limited Broadcast, RFC919
}

// nonGlobalIPv6CIDRs contains IANA IPv6 Special-Purpose Address Registry,
// where 'Global' flag is false.
//
// http://www.iana.org/assignments/iana-ipv6-special-registry/
var nonGlobalIPv6CIDRs = []string{
	"::1/128",       // Loopback Address, RFC4291
	"fc00::/7",      // Unique-Local, RFC4193
	"::ffff:0:0/96", // IPv4-mapped Address, RFC4291
	"fe80::/10",     // Linked-Scoped Unicast, RFC4291
	"::/128",        // Unspecified Address, RFC4291
	"2001::/23",     // IETF Protocol Assignments, RFC2928
	"2001:db8::/32", // Documentation, RFC3849
	"2001:2::/48",   // Benchmarking, RFC5180
	"2001::/32",     // TEREDO, RFC4380
	"100::/64",      // Discard-Only Address Block, RFC6666
}

// IsLocalIP tells if an IP address is not forwardable beyond a network.
func IsLocalIP(ip net.IP) bool {
	if ip == nil {
		return true
	}
	ip4 := ip.To4()
	if ip4 != nil {
		for _, inet := range nonGlobalIPv4Nets {
			if inet.Contains(ip4) {
				return true
			}
		}
		return false
	}
	ip6 := ip.To16()
	if ip6 != nil {
		for _, inet := range nonGlobalIPv6Nets {
			if inet.Contains(ip6) {
				return true
			}
		}
	}
	return false
}

// IsIP4 tells if a string is an IPv4 address.
func IsIP4(s string) bool {
	_, answer := ParseIP(s)
	return answer
}

// IsIP6 tells if a string is an IPv6 address.
func isIP6(s string) bool {
	ip, isV4 := ParseIP(s)
	return ip != nil && !isV4
}

// ParseIP is a wrapper around net.ParseIP and net.IP.To4
func ParseIP(s string) (ip net.IP, isIPv4 bool) {
	ip = net.ParseIP(s)
	if ip == nil {
		return
	}
	isIPv4 = ip.To4() != nil
	return
}
<commit_msg>Export IsIPv6()<commit_after>// Copyright (c) 2016 turbobytes
//
// This file is part of geoipdb, a library of GeoIP related helper functions
// for TurboBytes stack.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package iputils

import (
	"net"
)

func init() {
	// Initialize nonGlobalIPv*Nets
	nonGlobalIPv4Nets = make([]*net.IPNet, len(nonGlobalIPv4CIDRs))
	for i, cidr := range nonGlobalIPv4CIDRs {
		_, inet, err := net.ParseCIDR(cidr)
		if err != nil {
			panic(err)
		}
		nonGlobalIPv4Nets[i] = inet
	}
	nonGlobalIPv6Nets = make([]*net.IPNet, len(nonGlobalIPv6CIDRs))
	for i, cidr := range nonGlobalIPv6CIDRs {
		_, inet, err := net.ParseCIDR(cidr)
		if err != nil {
			panic(err)
		}
		nonGlobalIPv6Nets[i] = inet
	}
}

var (
	nonGlobalIPv4Nets []*net.IPNet
	nonGlobalIPv6Nets []*net.IPNet
)

// nonGlobalIPv4CIDRs contains IANA IPv4 Special-Purpose Address Registry,
// where 'Global' flag is false.
//
// http://www.iana.org/assignments/iana-ipv4-special-registry/
var nonGlobalIPv4CIDRs = []string{
	"127.0.0.0/8",        // Loopback, RFC1122
	"192.168.0.0/16",     // Private-Use, RFC1918
	"10.0.0.0/8",         // Private-Use, RFC1918
	"172.16.0.0/12",      // Private-Use, RFC1918
	"0.0.0.0/8",          // "This host on this network", RFC1122 section 3.2.1.3
	"100.64.0.0/10",      // Shared Address Space, RFC6598
	"169.254.0.0/16",     // Link Local, RFC3927
	"192.0.0.0/24",       // IETF Protocol Assignments, RFC6890
	"192.0.2.0/24",       // Documentation (TEST-NET-1), RFC5737
	"198.18.0.0/15",      // Benchmarking, RFC2544
	"198.51.100.0/24",    // Documentation (TEST-NET-2), RFC5737
	"203.0.113.0/24",     // Documentation (TEST-NET-3), RFC5737
	"240.0.0.0/4",        // Reserved, RFC1112
	"255.255.255.255/32", // Limited Broadcast, RFC919
}

// nonGlobalIPv6CIDRs contains IANA IPv6 Special-Purpose Address Registry,
// where 'Global' flag is false.
//
// http://www.iana.org/assignments/iana-ipv6-special-registry/
var nonGlobalIPv6CIDRs = []string{
	"::1/128",       // Loopback Address, RFC4291
	"fc00::/7",      // Unique-Local, RFC4193
	"::ffff:0:0/96", // IPv4-mapped Address, RFC4291
	"fe80::/10",     // Linked-Scoped Unicast, RFC4291
	"::/128",        // Unspecified Address, RFC4291
	"2001::/23",     // IETF Protocol Assignments, RFC2928
	"2001:db8::/32", // Documentation, RFC3849
	"2001:2::/48",   // Benchmarking, RFC5180
	"2001::/32",     // TEREDO, RFC4380
	"100::/64",      // Discard-Only Address Block, RFC6666
}

// IsLocalIP tells if an IP address is not forwardable across networks.
func IsLocalIP(ip net.IP) bool {
	if ip == nil {
		return true
	}
	ip4 := ip.To4()
	if ip4 != nil {
		for _, inet := range nonGlobalIPv4Nets {
			if inet.Contains(ip4) {
				return true
			}
		}
		return false
	}
	ip6 := ip.To16()
	if ip6 != nil {
		for _, inet := range nonGlobalIPv6Nets {
			if inet.Contains(ip6) {
				return true
			}
		}
	}
	return false
}

// IsIPv4 tells if a string is an IPv4 address.
func IsIPv4(s string) bool {
	_, answer := ParseIP(s)
	return answer
}

// IsIPv6 tells if a string is an IPv6 address.
func IsIPv6(s string) bool {
	ip, isIPv4 := ParseIP(s)
	return ip != nil && !isIPv4
}

// ParseIP is a wrapper around net.ParseIP and net.IP.To4
func ParseIP(s string) (ip net.IP, isIPv4 bool) {
	ip = net.ParseIP(s)
	if ip == nil {
		return
	}
	isIPv4 = ip.To4() != nil
	return
}
<|endoftext|>


<commit_before>package handler

import (
	"fmt"
	"github.com/vladpereskokov/Technopark_HighLoad-nginx/src/constants"
	modelServer "github.com/vladpereskokov/Technopark_HighLoad-nginx/src/models/server"
	"github.com/vladpereskokov/Technopark_HighLoad-nginx/src/utils"
	"log"
	"net"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

const HTTP_CONSTANTS_CONFIG = "configs/http.json"

type Handler struct {
	Connection net.Conn
	Request    *modelServer.Request
	Response   *modelServer.Response
	Constants  *modelServer.Constants
	Dir        string
}

type HandlerFunc func(chan net.Conn)

func CreateHandler(dir string) (handlerFunc HandlerFunc) {
	httpConstantsConfig := new(modelServer.Constants)

	err := utils.FromFile(HTTP_CONSTANTS_CONFIG, &httpConstantsConfig)
	if err != nil {
		log.Panicf("can not init http config: %v", err)
	}

	return func(channel chan net.Conn) {
		handler := Handler{}
		handler.create(httpConstantsConfig, dir)

		go handler.start(channel)
	}
}

func (handler *Handler) create(config *modelServer.Constants, dir string) {
	handler.Request = modelServer.InitRequest()
	handler.Response = modelServer.InitResponse()

	handler.Response.SetStatus(200, config.Statuses)

	handler.Constants = config
	handler.Dir = dir
}

func (handler *Handler) start(channel chan net.Conn) {
	for {
		handler.Connection = <-channel
		handler.handle()
	}
}

func (handler *Handler) handle() {
	handler.readRequest()
	handler.requestHandle()
	handler.writeResponse()
	handler.closeConn()
}

func (handler *Handler) readRequest() {
	buffer := make([]byte, 1024)

	_, err := handler.Connection.Read(buffer)
	if err != nil {
		fmt.Println("Error reading:", err.Error())

		return
	}

	handler.parseRequest(string(buffer))
}

func (handler *Handler) parseRequest(query string) {
	splitedQuery := strings.Split(query, "\r\n")[0]
	queryParts := strings.Split(splitedQuery, " ")

	if len(queryParts) != 3 {
		handler.Response.SetStatus(400, handler.Constants.Statuses)

		return
	}

	handler.Request.Method.SetMethod(queryParts[0])
	parsed_url, err := url.Parse(queryParts[1])

	if err != nil || !strings.HasPrefix(queryParts[2], "HTTP/") {
		handler.Response.SetStatus(400, handler.Constants.Statuses)
	}

	handler.Request.Url = parsed_url
}

func (handler *Handler) requestHandle() {
	if !handler.Response.IsOk() {
		handler.setContentHeaders(nil)
		return
	}

	if !handler.Constants.Methods.Contains(handler.Request.Method.Type) {
		handler.Response.SetStatus(405, handler.Constants.Statuses)
	} else {
		handler.preProcessPath()
	}
}

func (handler *Handler) preProcessPath() {
	handler.Request.SetPath(handler.Dir + handler.Request.GetPath())
	file_info := handler.check_path(false)

	if file_info != nil && file_info.IsDir() {
		handler.Request.SetPath(handler.Request.GetPath() + constants.INDEX_FILE)
		file_info = handler.check_path(true)
	}

	handler.setContentHeaders(file_info)
}

func (handler *Handler) check_path(is_dir bool) os.FileInfo {
	request_path := handler.Request.GetPath()

	fmt.Println(request_path)

	clear_path := path.Clean(request_path)
	handler.Request.SetPath(clear_path)

	info, err := os.Stat(request_path)
	if err != nil {
		if os.IsNotExist(err) && !is_dir {
			handler.Response.SetStatus(404, handler.Constants.Statuses)
		} else {
			handler.Response.SetStatus(403, handler.Constants.Statuses)
		}
	} else if !strings.Contains(clear_path, handler.Dir) {
		handler.Response.SetStatus(403, handler.Constants.Statuses)
	}
	return info
}

func (handler *Handler) setContentHeaders(info os.FileInfo) {
	if handler.Response.IsOk() {
		handler.Response.SetHeader("Content-Length", strconv.Itoa(int(info.Size())))
		handler.Response.SetHeader("Content-Type", handler.get_content_type())
	} else {
		handler.Response.SetHeader("Content-Length",
			strconv.Itoa(len(handler.Response.GetErrorBody(handler.Response.Status.Message))))
		handler.Response.SetHeader("Content-Type", constants.ERROR_BODY_MIME_TYPE)
	}
}

func (handler *Handler) get_content_type() string {
	extension := ""

	requestPath := handler.Request.GetPath()
	lastDot := strings.LastIndex(requestPath, ".")

	if lastDot >= 0 {
		extension = requestPath[lastDot:]
	}

	cType := handler.Constants.ContentTypes.GetType(extension)

	if len(cType) != 0 {
		return cType
	} else {
		return constants.DEFAULT_MIME_TYPE
	}
}

func (handler Handler) writeResponse() {
	handler.write(constants.HTTP_VERSION + " " + handler.Response.Status.Message)
	handler.writeHeader()
}

func (handler Handler) writeHeader() {
	handler.writeCommonHeaders()
	handler.writeSpecificHeaders()
	handler.write("")
	if handler.Request.Method.Type != "HEAD" {
		handler.writeBody()
	}
}

func (handler Handler) writeCommonHeaders() {
	handler.write("Date: " + time.Now().String())
	handler.write("Server: " + constants.SERVER)
	handler.write("Connection: close")
}

func (handler Handler) writeSpecificHeaders() {
	for key, value := range handler.Response.Headers {
		handler.write(key + ": " + value)
	}
}

func (handler Handler) writeBody() {
	if handler.Response.IsOk() {
		handler.writeOkBody()
	} else {
		handler.writeErrorBody()
	}
}

func (handler Handler) writeOkBody() {
	reader, err := handler.Response.GetOkBody(handler.Request.GetPath())
	if err != nil {
		fmt.Println("Can't open file ", handler.Request.GetPath())
		return
	}

	_, err = reader.WriteTo(handler.Connection)
	if err != nil {
		fmt.Println("Some error on read or write file ", handler.Request.GetPath())
	}
}

func (handler Handler) writeErrorBody() {
	body := handler.Response.GetErrorBody(handler.Response.Status.Message)

	handler.write(body)
}

func (handler Handler) write(content string) {
	handler.Connection.Write([]byte(content + "\r\n"))
}

func (handler *Handler) closeConn() {
	handler.Connection.Close()
}
<commit_msg>del path<commit_after>package handler

import (
	"fmt"
	"github.com/vladpereskokov/Technopark_HighLoad-nginx/src/constants"
	modelServer "github.com/vladpereskokov/Technopark_HighLoad-nginx/src/models/server"
	"github.com/vladpereskokov/Technopark_HighLoad-nginx/src/utils"
	"log"
	"net"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

const HTTP_CONSTANTS_CONFIG = "configs/http.json"

type Handler struct {
	Connection net.Conn
	Request    *modelServer.Request
	Response   *modelServer.Response
	Constants  *modelServer.Constants
	Dir        string
}

type HandlerFunc func(chan net.Conn)

func CreateHandler(dir string) (handlerFunc HandlerFunc) {
	httpConstantsConfig := new(modelServer.Constants)

	err := utils.FromFile(HTTP_CONSTANTS_CONFIG, &httpConstantsConfig)
	if err != nil {
		log.Panicf("can not init http config: %v", err)
	}

	return func(channel chan net.Conn) {
		handler := Handler{}
		handler.create(httpConstantsConfig, dir)

		go handler.start(channel)
	}
}

func (handler *Handler) create(config *modelServer.Constants, dir string) {
	handler.Request = modelServer.InitRequest()
	handler.Response = modelServer.InitResponse()

	handler.Response.SetStatus(200, config.Statuses)

	handler.Constants = config
	handler.Dir = dir
}

func (handler *Handler) start(channel chan net.Conn) {
	for {
		handler.Connection = <-channel
		handler.handle()
	}
}

func (handler *Handler) handle() {
	handler.readRequest()
	handler.requestHandle()
	handler.writeResponse()
	handler.closeConn()
}

func (handler *Handler) readRequest() {
	buffer := make([]byte, 1024)

	_, err := handler.Connection.Read(buffer)
	if err != nil {
		fmt.Println("Error reading:", err.Error())

		return
	}

	handler.parseRequest(string(buffer))
}

func (handler *Handler) parseRequest(query string) {
	splitedQuery := strings.Split(query, "\r\n")[0]
	queryParts := strings.Split(splitedQuery, " ")

	if len(queryParts) != 3 {
		handler.Response.SetStatus(400, handler.Constants.Statuses)

		return
	}

	handler.Request.Method.SetMethod(queryParts[0])
	parsed_url, err := url.Parse(queryParts[1])

	if err != nil || !strings.HasPrefix(queryParts[2], "HTTP/") {
		handler.Response.SetStatus(400, handler.Constants.Statuses)
	}

	handler.Request.Url = parsed_url
}

func (handler *Handler) requestHandle() {
	if !handler.Response.IsOk() {
		handler.setContentHeaders(nil)
		return
	}

	if !handler.Constants.Methods.Contains(handler.Request.Method.Type) {
		handler.Response.SetStatus(405, handler.Constants.Statuses)
	} else {
		handler.preProcessPath()
	}
}

func (handler *Handler) preProcessPath() {
	handler.Request.SetPath(handler.Dir + handler.Request.GetPath())
	file_info := handler.check_path(false)

	if file_info != nil && file_info.IsDir() {
		handler.Request.SetPath(handler.Request.GetPath() + constants.INDEX_FILE)
		file_info = handler.check_path(true)
	}

	handler.setContentHeaders(file_info)
}

func (handler *Handler) check_path(is_dir bool) os.FileInfo {
	request_path := handler.Request.GetPath()

	clear_path := path.Clean(request_path)
	handler.Request.SetPath(clear_path)

	info, err := os.Stat(request_path)
	if err != nil {
		if os.IsNotExist(err) && !is_dir {
			handler.Response.SetStatus(404, handler.Constants.Statuses)
		} else {
			handler.Response.SetStatus(403, handler.Constants.Statuses)
		}
	} else if !strings.Contains(clear_path, handler.Dir) {
		handler.Response.SetStatus(403, handler.Constants.Statuses)
	}
	return info
}

func (handler *Handler) setContentHeaders(info os.FileInfo) {
	if handler.Response.IsOk() {
		handler.Response.SetHeader("Content-Length", strconv.Itoa(int(info.Size())))
		handler.Response.SetHeader("Content-Type", handler.get_content_type())
	} else {
		handler.Response.SetHeader("Content-Length",
			strconv.Itoa(len(handler.Response.GetErrorBody(handler.Response.Status.Message))))
		handler.Response.SetHeader("Content-Type", constants.ERROR_BODY_MIME_TYPE)
	}
}

func (handler *Handler) get_content_type() string {
	extension := ""

	requestPath := handler.Request.GetPath()
	lastDot := strings.LastIndex(requestPath, ".")

	if lastDot >= 0 {
		extension = requestPath[lastDot:]
	}

	cType := handler.Constants.ContentTypes.GetType(extension)

	if len(cType) != 0 {
		return cType
	} else {
		return constants.DEFAULT_MIME_TYPE
	}
}

func (handler Handler) writeResponse() {
	handler.write(constants.HTTP_VERSION + " " + handler.Response.Status.Message)
	handler.writeHeader()
}

func (handler Handler) writeHeader() {
	handler.writeCommonHeaders()
	handler.writeSpecificHeaders()
	handler.write("")
	if handler.Request.Method.Type != "HEAD" {
		handler.writeBody()
	}
}

func (handler Handler) writeCommonHeaders() {
	handler.write("Date: " + time.Now().String())
	handler.write("Server: " + constants.SERVER)
	handler.write("Connection: close")
}

func (handler Handler) writeSpecificHeaders() {
	for key, value := range handler.Response.Headers {
		handler.write(key + ": " + value)
	}
}

func (handler Handler) writeBody() {
	if handler.Response.IsOk() {
		handler.writeOkBody()
	} else {
		handler.writeErrorBody()
	}
}

func (handler Handler) writeOkBody() {
	reader, err := handler.Response.GetOkBody(handler.Request.GetPath())
	if err != nil {
		fmt.Println("Can't open file ", handler.Request.GetPath())
		return
	}

	_, err = reader.WriteTo(handler.Connection)
	if err != nil {
		fmt.Println("Some error on read or write file ", handler.Request.GetPath())
	}
}

func (handler Handler) writeErrorBody() {
	body := handler.Response.GetErrorBody(handler.Response.Status.Message)

	handler.write(body)
}

func (handler Handler) write(content string) {
	handler.Connection.Write([]byte(content + "\r\n"))
}

func (handler *Handler) closeConn() {
	handler.Connection.Close()
}
<|endoftext|>


<commit_before>package cmd

import (
	"crypto/tls"
	"net/smtp"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/go-errors/errors"
	"github.com/mitchellh/mapstructure"
	irma "github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/keyshare"
	"github.com/spf13/cast"
	"github.com/spf13/pflag"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func configureEmail() keyshare.EmailConfiguration {
	// If username/password are specified for the email server, build an authentication object.
	var emailAuth smtp.Auth
	if viper.GetString("email_username") != "" {
		emailAuth = smtp.PlainAuth(
			"",
			viper.GetString("email_username"),
			viper.GetString("email_password"),
			viper.GetString("email_hostname"),
		)
	}

	return keyshare.EmailConfiguration{
		EmailServer:     viper.GetString("email_server"),
		EmailAuth:       emailAuth,
		EmailFrom:       viper.GetString("email_from"),
		DefaultLanguage: viper.GetString("default_language"),
	}
}

func configureIRMAServer() *server.Configuration {
	return &server.Configuration{
		SchemesPath:            viper.GetString("schemes_path"),
		SchemesAssetsPath:      viper.GetString("schemes_assets_path"),
		SchemesUpdateInterval:  viper.GetInt("schemes_update"),
		DisableSchemesUpdate:   viper.GetInt("schemes_update") == 0,
		IssuerPrivateKeysPath:  viper.GetString("privkeys"),
		RevocationDBType:       viper.GetString("revocation_db_type"),
		RevocationDBConnStr:    viper.GetString("revocation_db_str"),
		RevocationSettings:     irma.RevocationSettings{},
		URL:                    viper.GetString("url"),
		DisableTLS:             viper.GetBool("no_tls"),
		Email:                  viper.GetString("email"),
		EnableSSE:              viper.GetBool("sse"),
		Verbose:                viper.GetInt("verbose"),
		Quiet:                  viper.GetBool("quiet"),
		LogJSON:                viper.GetBool("log_json"),
		Logger:                 logger,
		Production:             viper.GetBool("production"),
		MaxSessionLifetime:     viper.GetInt("max_session_lifetime"),
		JwtIssuer:              viper.GetString("jwt_issuer"),
		JwtPrivateKey:          viper.GetString("jwt_privkey"),
		JwtPrivateKeyFile:      viper.GetString("jwt_privkey_file"),
		AllowUnsignedCallbacks: viper.GetBool("allow_unsigned_callbacks"),
		AugmentClientReturnURL: viper.GetBool("augment_client_return_url"),
	}
}

func configureTLS() *tls.Config {
	conf, err := server.TLSConf(
		viper.GetString("tls_cert"),
		viper.GetString("tls_cert_file"),
		viper.GetString("tls_privkey"),
		viper.GetString("tls_privkey_file"))
	if err != nil {
		die("", err)
	}
	return conf
}

func readConfig(cmd *cobra.Command, name, logname string, configpaths []string, productionDefaults map[string]interface{}) {
	dashReplacer := strings.NewReplacer("-", "_")
	viper.SetEnvKeyReplacer(dashReplacer)
	viper.SetEnvPrefix(strings.ToUpper(name))
	viper.AutomaticEnv()

	// bind cmd flags to viper, replacing dashes with underscores
	f := cmd.Flags()
	normalizeFunc := f.GetNormalizeFunc()
	f.SetNormalizeFunc(func(fs *pflag.FlagSet, name string) pflag.NormalizedName {
		result := normalizeFunc(fs, name)
		name = strings.ReplaceAll(string(result), "-", "_")
		return pflag.NormalizedName(name)
	})
	if err := viper.BindPFlags(f); err != nil {
		die("", err)
	}

	// Locate and read configuration file
	confpath := viper.GetString("config")
	if confpath != "" {
		info, err := os.Stat(confpath)
		if err != nil {
			if os.IsNotExist(err) {
				die("specified configuration file does not exist", nil)
			} else {
				die("failed to stat configuration file", err)
			}
		}
		if info.IsDir() {
			die("specified configuration file is a directory", nil)
		}
		dir, file := filepath.Dir(confpath), filepath.Base(confpath)
		viper.SetConfigName(strings.TrimSuffix(file, filepath.Ext(file)))
		viper.AddConfigPath(dir)
	} else {
		viper.SetConfigName(name)
		for _, path := range configpaths {
			viper.AddConfigPath(path)
		}
	}

	err := viper.ReadInConfig() // Hold error checking until we know how much of it to log

	// Create our logger instance
	logger = server.NewLogger(viper.GetInt("verbose"), viper.GetBool("quiet"), viper.GetBool("log_json"))

	// First log output: hello, development or production mode, log level
	mode := "development"
	if viper.GetBool("production") {
		mode = "production"
		for key, val := range productionDefaults {
			viper.SetDefault(key, val)
		}
	}
	logger.WithFields(logrus.Fields{
		"version":   irma.Version,
		"mode":      mode,
		"verbosity": server.Verbosity(viper.GetInt("verbose")),
	}).Info(logname + " running")

	// Now we finally examine and log any error from viper.ReadInConfig()
	if err != nil {
		if _, notfound := err.(viper.ConfigFileNotFoundError); notfound {
			logger.Info("No configuration file found")
		} else {
			die("", errors.WrapPrefix(err, "Failed to unmarshal configuration file at "+viper.ConfigFileUsed(), 0))
		}
	} else {
		logger.Info("Config file: ", viper.ConfigFileUsed())
	}
}

func handleMapOrString(key string, dest interface{}) error {
	var m map[string]interface{}
	var err error
	if val, flagOrEnv := viper.Get(key).(string); !flagOrEnv || val != "" {
		if m, err = cast.ToStringMapE(viper.Get(key)); err != nil {
			return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from flag or env var", 0)
		}
	}
	if len(m) == 0 {
		return nil
	}
	if err := mapstructure.Decode(m, dest); err != nil {
		return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from config file", 0)
	}
	return nil
}

func handlePermission(typ string) []string {
	if !viper.IsSet(typ) {
		if typ == "revoke_perms" || (viper.GetBool("production") && typ == "issue_perms") {
			return []string{}
		} else {
			return []string{"*"}
		}
	}
	perms := viper.GetStringSlice(typ)
	if perms == nil {
		return []string{}
	}
	return perms
}

// productionMode examines the arguments passed to the executable to see if --production is enabled.
// (This should really be done using viper, but when the help message is printed, viper is not yet
// initialized.)
func productionMode() bool {
	r := regexp.MustCompile("^--production(=(.*))?$")
	for _, arg := range os.Args {
		matches := r.FindStringSubmatch(arg)
		if len(matches) != 3 {
			continue
		}
		if matches[1] == "" {
			return true
		}
		return checkConfVal(matches[2])
	}

	return checkConfVal(os.Getenv("IRMASERVER_PRODUCTION"))
}

func checkConfVal(val string) bool {
	lc := strings.ToLower(val)
	return lc == "1" || lc == "true" || lc == "yes" || lc == "t"
}
<commit_msg>refactor: reuse already defined dashReplacer in viper config normalization function<commit_after>package cmd

import (
	"crypto/tls"
	"net/smtp"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/go-errors/errors"
	"github.com/mitchellh/mapstructure"
	irma "github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/keyshare"
	"github.com/spf13/cast"
	"github.com/spf13/pflag"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func configureEmail() keyshare.EmailConfiguration {
	// If username/password are specified for the email server, build an authentication object.
	var emailAuth smtp.Auth
	if viper.GetString("email_username") != "" {
		emailAuth = smtp.PlainAuth(
			"",
			viper.GetString("email_username"),
			viper.GetString("email_password"),
			viper.GetString("email_hostname"),
		)
	}

	return keyshare.EmailConfiguration{
		EmailServer:     viper.GetString("email_server"),
		EmailAuth:       emailAuth,
		EmailFrom:       viper.GetString("email_from"),
		DefaultLanguage: viper.GetString("default_language"),
	}
}

func configureIRMAServer() *server.Configuration {
	return &server.Configuration{
		SchemesPath:            viper.GetString("schemes_path"),
		SchemesAssetsPath:      viper.GetString("schemes_assets_path"),
		SchemesUpdateInterval:  viper.GetInt("schemes_update"),
		DisableSchemesUpdate:   viper.GetInt("schemes_update") == 0,
		IssuerPrivateKeysPath:  viper.GetString("privkeys"),
		RevocationDBType:       viper.GetString("revocation_db_type"),
		RevocationDBConnStr:    viper.GetString("revocation_db_str"),
		RevocationSettings:     irma.RevocationSettings{},
		URL:                    viper.GetString("url"),
		DisableTLS:             viper.GetBool("no_tls"),
		Email:                  viper.GetString("email"),
		EnableSSE:              viper.GetBool("sse"),
		Verbose:                viper.GetInt("verbose"),
		Quiet:                  viper.GetBool("quiet"),
		LogJSON:                viper.GetBool("log_json"),
		Logger:                 logger,
		Production:             viper.GetBool("production"),
		MaxSessionLifetime:     viper.GetInt("max_session_lifetime"),
		JwtIssuer:              viper.GetString("jwt_issuer"),
		JwtPrivateKey:          viper.GetString("jwt_privkey"),
		JwtPrivateKeyFile:      viper.GetString("jwt_privkey_file"),
		AllowUnsignedCallbacks: viper.GetBool("allow_unsigned_callbacks"),
		AugmentClientReturnURL: viper.GetBool("augment_client_return_url"),
	}
}

func configureTLS() *tls.Config {
	conf, err := server.TLSConf(
		viper.GetString("tls_cert"),
		viper.GetString("tls_cert_file"),
		viper.GetString("tls_privkey"),
		viper.GetString("tls_privkey_file"))
	if err != nil {
		die("", err)
	}
	return conf
}

func readConfig(cmd *cobra.Command, name, logname string, configpaths []string, productionDefaults map[string]interface{}) {
	dashReplacer := strings.NewReplacer("-", "_")
	viper.SetEnvKeyReplacer(dashReplacer)
	viper.SetEnvPrefix(strings.ToUpper(name))
	viper.AutomaticEnv()

	// Bind cmd flags to viper, such that configuration files use underscores instead of dashes
	f := cmd.Flags()
	normalizeFunc := f.GetNormalizeFunc()
	f.SetNormalizeFunc(func(fs *pflag.FlagSet, name string) pflag.NormalizedName {
		return pflag.NormalizedName(dashReplacer.Replace(string(normalizeFunc(fs, name))))
	})
	if err := viper.BindPFlags(f); err != nil {
		die("", err)
	}

	// Locate and read configuration file
	confpath := viper.GetString("config")
	if confpath != "" {
		info, err := os.Stat(confpath)
		if err != nil {
			if os.IsNotExist(err) {
				die("specified configuration file does not exist", nil)
			} else {
				die("failed to stat configuration file", err)
			}
		}
		if info.IsDir() {
			die("specified configuration file is a directory", nil)
		}
		dir, file := filepath.Dir(confpath), filepath.Base(confpath)
		viper.SetConfigName(strings.TrimSuffix(file, filepath.Ext(file)))
		viper.AddConfigPath(dir)
	} else {
		viper.SetConfigName(name)
		for _, path := range configpaths {
			viper.AddConfigPath(path)
		}
	}

	err := viper.ReadInConfig() // Hold error checking until we know how much of it to log

	// Create our logger instance
	logger = server.NewLogger(viper.GetInt("verbose"), viper.GetBool("quiet"), viper.GetBool("log_json"))

	// First log output: hello, development or production mode, log level
	mode := "development"
	if viper.GetBool("production") {
		mode = "production"
		for key, val := range productionDefaults {
			viper.SetDefault(key, val)
		}
	}
	logger.WithFields(logrus.Fields{
		"version":   irma.Version,
		"mode":      mode,
		"verbosity": server.Verbosity(viper.GetInt("verbose")),
	}).Info(logname + " running")

	// Now we finally examine and log any error from viper.ReadInConfig()
	if err != nil {
		if _, notfound := err.(viper.ConfigFileNotFoundError); notfound {
			logger.Info("No configuration file found")
		} else {
			die("", errors.WrapPrefix(err, "Failed to unmarshal configuration file at "+viper.ConfigFileUsed(), 0))
		}
	} else {
		logger.Info("Config file: ", viper.ConfigFileUsed())
	}
}

func handleMapOrString(key string, dest interface{}) error {
	var m map[string]interface{}
	var err error
	if val, flagOrEnv := viper.Get(key).(string); !flagOrEnv || val != "" {
		if m, err = cast.ToStringMapE(viper.Get(key)); err != nil {
			return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from flag or env var", 0)
		}
	}
	if len(m) == 0 {
		return nil
	}
	if err := mapstructure.Decode(m, dest); err != nil {
		return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from config file", 0)
	}
	return nil
}

func handlePermission(typ string) []string {
	if !viper.IsSet(typ) {
		if typ == "revoke_perms" || (viper.GetBool("production") && typ == "issue_perms") {
			return []string{}
		} else {
			return []string{"*"}
		}
	}
	perms := viper.GetStringSlice(typ)
	if perms == nil {
		return []string{}
	}
	return perms
}

// productionMode examines the arguments passed to the executable to see if --production is enabled.
// (This should really be done using viper, but when the help message is printed, viper is not yet
// initialized.)
func productionMode() bool {
	r := regexp.MustCompile("^--production(=(.*))?$")
	for _, arg := range os.Args {
		matches := r.FindStringSubmatch(arg)
		if len(matches) != 3 {
			continue
		}
		if matches[1] == "" {
			return true
		}
		return checkConfVal(matches[2])
	}

	return checkConfVal(os.Getenv("IRMASERVER_PRODUCTION"))
}

func checkConfVal(val string) bool {
	lc := strings.ToLower(val)
	return lc == "1" || lc == "true" || lc == "yes" || lc == "t"
}
<|endoftext|>


<commit_before>package client_tests

import (
	"database/sql"
	"fmt"

	log "github.com/apache/incubator-trafficcontrol/lib/go-log"
	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
)

func prepareDatabaseTest(cfg *Config) {
	fmt.Printf("cfg ---> %v\n", cfg)
}
func prepareDatabase(cfg *Config) {

	fmt.Printf("cfg ---> %v\n", cfg)
	var db *sql.DB
	var err error

	sslStr := "require"
	if !cfg.DB.SSL {
		sslStr = "disable"
	}

	db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", cfg.DB.User, cfg.DB.Password, cfg.DB.Hostname, cfg.DB.DBName, sslStr))
	if err != nil {
		log.Errorf("opening database: %v\n", err)
		return
	}

	//res, err = tx.Exec("CREATE EXTENSION IF NOT EXISTS pgcrypto")
	//if err != nil {
	//log.Errorf("Transaction Failed %v %v", err, res)
	//}

	defer db.Close()
	tx, err := db.Begin()
	if err != nil {
		log.Errorf("Transaction Failed", err)
	}
	res, err := tx.Exec("DELETE FROM JOB")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	//db.MustExec("insert into role (name, description, priv_level) VALUES ($1, $2, $3, $4)", "disallowed", "Block all access", "0")
	// Role
	res, err = tx.Exec("DELETE FROM ROLE")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (1, 'disallowed','Block all access',0) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (2, 'read-only user','Block all access', 10) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (3, 'operations','Block all access', 20) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (4, 'admin','super-user', 30) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (5, 'portal','Portal User', 2) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (6, 'migrations','database migrations user - DO NOT REMOVE', 20) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (7, 'federation','Role for Secondary CZF', 15) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	// Tmuser
	res, err = tx.Exec("DELETE FROM LOG")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("DELETE FROM TM_USER")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	encryptedPassword, err := auth.DerivePassword(cfg.TOUserPassword)
	if err != nil {
		log.Errorf("Password encryption failed %v %v", err)
	}
	userInsert := `INSERT INTO tm_user (username, local_passwd, confirm_local_passwd, role) VALUES ('admin','` + encryptedPassword + `','` + encryptedPassword + `', 4)`
	res, err = tx.Exec(userInsert)
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	tx.Commit()
	if err != nil {
		log.Infof(err.Error())
	}
}
<commit_msg>cleaned up unused func<commit_after>package client_tests

import (
	"database/sql"
	"fmt"

	log "github.com/apache/incubator-trafficcontrol/lib/go-log"
	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
)

func prepareDatabase(cfg *Config) {

	fmt.Printf("cfg ---> %v\n", cfg)
	var db *sql.DB
	var err error

	sslStr := "require"
	if !cfg.DB.SSL {
		sslStr = "disable"
	}

	db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", cfg.DB.User, cfg.DB.Password, cfg.DB.Hostname, cfg.DB.DBName, sslStr))
	if err != nil {
		log.Errorf("opening database: %v\n", err)
		return
	}

	//res, err = tx.Exec("CREATE EXTENSION IF NOT EXISTS pgcrypto")
	//if err != nil {
	//log.Errorf("Transaction Failed %v %v", err, res)
	//}

	defer db.Close()
	tx, err := db.Begin()
	if err != nil {
		log.Errorf("Transaction Failed", err)
	}
	res, err := tx.Exec("DELETE FROM JOB")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	//db.MustExec("insert into role (name, description, priv_level) VALUES ($1, $2, $3, $4)", "disallowed", "Block all access", "0")
	// Role
	res, err = tx.Exec("DELETE FROM ROLE")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (1, 'disallowed','Block all access',0) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (2, 'read-only user','Block all access', 10) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (3, 'operations','Block all access', 20) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (4, 'admin','super-user', 30) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (5, 'portal','Portal User', 2) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (6, 'migrations','database migrations user - DO NOT REMOVE', 20) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("insert into role (id, name, description, priv_level) values (7, 'federation','Role for Secondary CZF', 15) ON CONFLICT DO NOTHING")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	// Tmuser
	res, err = tx.Exec("DELETE FROM LOG")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	res, err = tx.Exec("DELETE FROM TM_USER")
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}
	encryptedPassword, err := auth.DerivePassword(cfg.TOUserPassword)
	if err != nil {
		log.Errorf("Password encryption failed %v %v", err)
	}
	userInsert := `INSERT INTO tm_user (username, local_passwd, confirm_local_passwd, role) VALUES ('admin','` + encryptedPassword + `','` + encryptedPassword + `', 4)`
	res, err = tx.Exec(userInsert)
	if err != nil {
		log.Errorf("Transaction Failed %v %v", err, res)
	}

	tx.Commit()
	if err != nil {
		log.Infof(err.Error())
	}
}
<|endoftext|>