func (s *OffsetStash) ResetOffset(msg *sarama.ConsumerMessage, metadata string) {
	s.ResetPartitionOffset(msg.Topic, msg.Partition, msg.Offset, metadata)
}

func ( s * OffsetStash ) ResetOffset ( msg * sarama . ConsumerMessage , metadata string ) { s . ResetPartitionOffset ( msg . Topic , msg . Partition , msg . Offset , metadata ) }

// ResetOffset stashes the provided message offset
// See ResetPartitionOffset for explanation

ResetOffset stashes the provided message offset See ResetPartitionOffset for explanation


func (s *OffsetStash) Offsets() map[string]int64 {
	s.mu.Lock()
	defer s.mu.Unlock()

	res := make(map[string]int64, len(s.offsets))
	for tp, info := range s.offsets {
		res[tp.String()] = info.Offset
	}
	return res
}

func ( s * OffsetStash ) Offsets ( ) map [ string ] int64 { s . mu . Lock ( ) defer s . mu . Unlock ( ) res := make ( map [ string ] int64 , len ( s . offsets ) ) for tp , info := range s . offsets { res [ tp . String ( ) ] = info . Offset } return res }

// Offsets returns the latest stashed offsets by topic-partition

Offsets returns the latest stashed offsets by topic - partition


func (r *InstanceGroup) Actual(immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("instanceGroup.Actual")
	if r.CachedActual != nil {
		logger.Debug("Using cached instance [actual]")
		return immutable, r.CachedActual, nil
	}
	newResource := &InstanceGroup{
		Shared: Shared{
			Name:    r.Name,
			CloudID: r.ServerPool.Identifier,
		},
	}

	project, err := Sdk.Service.Projects.Get(immutable.ProviderConfig().CloudId).Do()
	if err != nil && project != nil {
		instances, err := Sdk.Service.Instances.List(immutable.ProviderConfig().CloudId, immutable.ProviderConfig().Location).Do()
		if err != nil {
			return nil, nil, err
		}

		count := len(instances.Items)
		if count > 0 {
			newResource.Count = count

			instance := instances.Items[0]
			newResource.Name = instance.Name
			newResource.CloudID = string(instance.Id)
			newResource.Size = instance.Kind
			newResource.Image = r.Image
			newResource.Location = instance.Zone
		}
	}

	newResource.BootstrapScripts = r.ServerPool.BootstrapScripts
	newResource.SSHFingerprint = immutable.ProviderConfig().SSH.PublicKeyFingerprint
	newResource.Name = r.Name
	r.CachedActual = newResource
	return immutable, newResource, nil
}

func ( r * InstanceGroup ) Actual ( immutable * cluster . Cluster ) ( * cluster . Cluster , cloud . Resource , error ) { logger . Debug ( " " ) if r . CachedActual != nil { logger . Debug ( " " ) return immutable , r . CachedActual , nil } newResource := & InstanceGroup { Shared : Shared { Name : r . Name , CloudID : r . ServerPool . Identifier , } , } project , err := Sdk . Service . Projects . Get ( immutable . ProviderConfig ( ) . CloudId ) . Do ( ) if err != nil && project != nil { instances , err := Sdk . Service . Instances . List ( immutable . ProviderConfig ( ) . CloudId , immutable . ProviderConfig ( ) . Location ) . Do ( ) if err != nil { return nil , nil , err } count := len ( instances . Items ) if count > 0 { newResource . Count = count instance := instances . Items [ 0 ] newResource . Name = instance . Name newResource . CloudID = string ( instance . Id ) newResource . Size = instance . Kind newResource . Image = r . Image newResource . Location = instance . Zone } } newResource . BootstrapScripts = r . ServerPool . BootstrapScripts newResource . SSHFingerprint = immutable . ProviderConfig ( ) . SSH . PublicKeyFingerprint newResource . Name = r . Name r . CachedActual = newResource return immutable , newResource , nil }

// Actual is used to build a cluster based on instances on the cloud provider.

Actual is used to build a cluster based on instances on the cloud provider .


func (r *InstanceGroup) Expected(immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("instanceGroup.Expected")
	if r.CachedExpected != nil {
		logger.Debug("Using instance subnet [expected]")
		return immutable, r.CachedExpected, nil
	}
	expected := &InstanceGroup{
		Shared: Shared{
			Name:    r.Name,
			CloudID: r.ServerPool.Identifier,
		},
		Size:             r.ServerPool.Size,
		Location:         immutable.ProviderConfig().Location,
		Image:            r.ServerPool.Image,
		Count:            r.ServerPool.MaxCount,
		SSHFingerprint:   immutable.ProviderConfig().SSH.PublicKeyFingerprint,
		BootstrapScripts: r.ServerPool.BootstrapScripts,
	}
	r.CachedExpected = expected
	return immutable, expected, nil
}

func ( r * InstanceGroup ) Expected ( immutable * cluster . Cluster ) ( * cluster . Cluster , cloud . Resource , error ) { logger . Debug ( " " ) if r . CachedExpected != nil { logger . Debug ( " " ) return immutable , r . CachedExpected , nil } expected := & InstanceGroup { Shared : Shared { Name : r . Name , CloudID : r . ServerPool . Identifier , } , Size : r . ServerPool . Size , Location : immutable . ProviderConfig ( ) . Location , Image : r . ServerPool . Image , Count : r . ServerPool . MaxCount , SSHFingerprint : immutable . ProviderConfig ( ) . SSH . PublicKeyFingerprint , BootstrapScripts : r . ServerPool . BootstrapScripts , } r . CachedExpected = expected return immutable , expected , nil }

// Expected is used to build a cluster expected to be on the cloud provider.

Expected is used to build a cluster expected to be on the cloud provider .


func (r *InstanceGroup) Delete(actual cloud.Resource, immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("instanceGroup.Delete")
	deleteResource := actual.(*InstanceGroup)
	if deleteResource.Name == "" {
		return nil, nil, fmt.Errorf("Unable to delete instance resource without Name [%s]", deleteResource.Name)
	}

	logger.Success("Deleting InstanceGroup manager [%s]", r.ServerPool.Name)
	_, err := Sdk.Service.InstanceGroupManagers.Get(immutable.ProviderConfig().CloudId, immutable.ProviderConfig().Location, strings.ToLower(r.ServerPool.Name)).Do()
	if err == nil {
		_, err := Sdk.Service.InstanceGroupManagers.Delete(immutable.ProviderConfig().CloudId, immutable.ProviderConfig().Location, strings.ToLower(r.ServerPool.Name)).Do()
		if err != nil {
			return nil, nil, err
		}
	}

	_, err = Sdk.Service.InstanceTemplates.Get(immutable.ProviderConfig().CloudId, strings.ToLower(r.ServerPool.Name)).Do()
	if err == nil {
		err := r.retryDeleteInstanceTemplate(immutable)
		if err != nil {
			return nil, nil, err
		}
	}

	// Kubernetes API
	providerConfig := immutable.ProviderConfig()
	providerConfig.KubernetesAPI.Endpoint = ""
	immutable.SetProviderConfig(providerConfig)
	renderedCluster, err := r.immutableRender(actual, immutable)
	if err != nil {
		return nil, nil, err
	}
	return renderedCluster, actual, nil
}

func
(
r
*
InstanceGroup
)
Delete
(
actual
cloud
.
Resource
,
immutable
*
cluster
.
Cluster
)
(
*
cluster
.
Cluster
,
cloud
.
Resource
,
error
)
{
logger
.
Debug
(
"
"
)
deleteResource
:=
actual
.
(
*
InstanceGroup
)
if
deleteResource
.
Name
==
"
"
{
return
,
,
fmt
.
Errorf
(
"
"
,
deleteResource
.
Name
)
}
logger
.
Success
(
"
"
,
r
.
ServerPool
.
Name
)
_
,
err
:=
Sdk
.
Service
.
InstanceGroupManagers
.
Get
(
immutable
.
ProviderConfig
(
)
.
CloudId
,
immutable
.
ProviderConfig
(
)
.
Location
,
strings
.
ToLower
(
r
.
ServerPool
.
Name
)
)
.
Do
(
)
if
err
==
{
_
,
err
:=
Sdk
.
Service
.
InstanceGroupManagers
.
Delete
(
immutable
.
ProviderConfig
(
)
.
CloudId
,
immutable
.
ProviderConfig
(
)
.
Location
,
strings
.
ToLower
(
r
.
ServerPool
.
Name
)
)
.
Do
(
)
if
err
!=
{
return
,
,
err
}
}
_
,
err
=
Sdk
.
Service
.
InstanceTemplates
.
Get
(
immutable
.
ProviderConfig
(
)
.
CloudId
,
strings
.
ToLower
(
r
.
ServerPool
.
Name
)
)
.
Do
(
)
if
err
==
{
err
:=
r
.
retryDeleteInstanceTemplate
(
immutable
)
if
err
!=
{
return
,
,
err
}
}
// Kubernetes API
providerConfig
:=
immutable
.
ProviderConfig
(
)
providerConfig
.
KubernetesAPI
.
Endpoint
=
"
"
immutable
.
SetProviderConfig
(
providerConfig
)
renderedCluster
,
err
:=
r
.
immutableRender
(
actual
,
immutable
)
if
err
!=
{
return
,
,
err
}
return
renderedCluster
,
actual
,
}

// Delete is used to delete the instances on the cloud provider


func GetReconciler(known *cluster.Cluster, runtimeParameters *RuntimeParameters) (reconciler cloud.Reconciler, err error) {
	switch known.ProviderConfig().Cloud {
	case cluster.CloudGoogle:
		sdk, err := googleSDK.NewSdk()
		if err != nil {
			return nil, err
		}
		gr.Sdk = sdk
		return cloud.NewAtomicReconciler(known, compute.NewGoogleComputeModel(known)), nil
	case cluster.CloudDigitalOcean:
		sdk, err := godoSdk.NewSdk()
		if err != nil {
			return nil, err
		}
		dr.Sdk = sdk
		return cloud.NewAtomicReconciler(known, droplet.NewDigitalOceanDropletModel(known)), nil
	case cluster.CloudAmazon:
		awsProfile := ""
		if runtimeParameters != nil {
			awsProfile = runtimeParameters.AwsProfile
		}
		sdk, err := awsSdkGo.NewSdk(known.ProviderConfig().Location, awsProfile)
		if err != nil {
			return nil, err
		}
		ar.Sdk = sdk
		return cloud.NewAtomicReconciler(known, awspub.NewAmazonPublicModel(known)), nil
	case cluster.CloudAzure:
		sdk, err := azureSDK.NewSdk()
		if err != nil {
			return nil, err
		}
		azr.Sdk = sdk
		return cloud.NewAtomicReconciler(known, azpub.NewAzurePublicModel(known)), nil
	case cluster.CloudOVH:
		sdk, err := openstackSdk.NewSdk(known.ProviderConfig().Location)
		if err != nil {
			return nil, err
		}
		osr.Sdk = sdk
		return cloud.NewAtomicReconciler(known, osovh.NewOvhPublicModel(known)), nil
	case cluster.CloudPacket:
		sdk, err := packetSDK.NewSdk()
		if err != nil {
			return nil, err
		}
		packetr.Sdk = sdk
		return cloud.NewAtomicReconciler(known, packetpub.NewPacketPublicModel(known)), nil
	case cluster.CloudECS:
		sdk, err := openstackSdk.NewSdk(known.ProviderConfig().Location)
		if err != nil {
			return nil, err
		}
		osr.Sdk = sdk
		return cloud.NewAtomicReconciler(known, osecs.NewEcsPublicModel(known)), nil
	default:
		return nil, fmt.Errorf("Invalid cloud type: %s", known.ProviderConfig().Cloud)
	}
}

func GetReconciler ( known * cluster . Cluster , runtimeParameters * RuntimeParameters ) ( reconciler cloud . Reconciler , err error ) { switch known . ProviderConfig ( ) . Cloud { case cluster . CloudGoogle : sdk , err := googleSDK . NewSdk ( ) if err != nil { return nil , err } gr . Sdk = sdk return cloud . NewAtomicReconciler ( known , compute . NewGoogleComputeModel ( known ) ) , nil case cluster . CloudDigitalOcean : sdk , err := godoSdk . NewSdk ( ) if err != nil { return nil , err } dr . Sdk = sdk return cloud . NewAtomicReconciler ( known , droplet . NewDigitalOceanDropletModel ( known ) ) , nil case cluster . CloudAmazon : awsProfile := " " if runtimeParameters != nil { awsProfile = runtimeParameters . AwsProfile } sdk , err := awsSdkGo . NewSdk ( known . ProviderConfig ( ) . Location , awsProfile ) if err != nil { return nil , err } ar . Sdk = sdk return cloud . NewAtomicReconciler ( known , awspub . NewAmazonPublicModel ( known ) ) , nil case cluster . CloudAzure : sdk , err := azureSDK . NewSdk ( ) if err != nil { return nil , err } azr . Sdk = sdk return cloud . NewAtomicReconciler ( known , azpub . NewAzurePublicModel ( known ) ) , nil case cluster . CloudOVH : sdk , err := openstackSdk . NewSdk ( known . ProviderConfig ( ) . Location ) if err != nil { return nil , err } osr . Sdk = sdk return cloud . NewAtomicReconciler ( known , osovh . NewOvhPublicModel ( known ) ) , nil case cluster . CloudPacket : sdk , err := packetSDK . NewSdk ( ) if err != nil { return nil , err } packetr . Sdk = sdk return cloud . NewAtomicReconciler ( known , packetpub . NewPacketPublicModel ( known ) ) , nil case cluster . CloudECS : sdk , err := openstackSdk . NewSdk ( known . ProviderConfig ( ) . Location ) if err != nil { return nil , err } osr . Sdk = sdk return cloud . NewAtomicReconciler ( known , osecs . NewEcsPublicModel ( known ) ) , nil default : return nil , fmt . Errorf ( " " , known . ProviderConfig ( ) . Cloud ) } }

// GetReconciler gets the correct Reconciler for the cloud provider currenty used.

GetReconciler gets the correct Reconciler for the cloud provider currenty used .


func GetVersion() *Version {
	return &Version{
		Version:   KubicornVersion,
		GitCommit: GitSha,
		BuildDate: time.Now().UTC().String(),
		GoVersion: runtime.Version(),
		GOOS:      runtime.GOOS,
		GOArch:    runtime.GOARCH,
	}
}

func GetVersion ( ) * Version { return & Version { Version : KubicornVersion , GitCommit : GitSha , BuildDate : time . Now ( ) . UTC ( ) . String ( ) , GoVersion : runtime . Version ( ) , GOOS : runtime . GOOS , GOArch : runtime . GOARCH , } }


func GetVersionJSON() string {
	verBytes, err := json.Marshal(GetVersion())
	if err != nil {
		logger.Critical("Unable to marshal version struct: %v", err)
	}
	return string(verBytes)
}

func GetVersionJSON ( ) string { verBytes , err := json . Marshal ( GetVersion ( ) ) if err != nil { logger . Critical ( " " , err ) } return string ( verBytes ) }

// GetVersionJSON returns Kubicorn version in JSON format.

GetVersionJSON returns Kubicorn version in JSON format .


func (r *ResourceGroup) Actual(immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("resourcegroup.Actual")
	newResource := &ResourceGroup{
		Shared: Shared{
			Name:       r.Name,
			Tags:       r.Tags,
			Identifier: immutable.ProviderConfig().GroupIdentifier,
		},
		Location: r.Location,
	}

	if r.Identifier != "" {
		group, err := Sdk.ResourceGroup.Get(immutable.Name)
		if err != nil {
			return nil, nil, err
		}
		newResource.Location = *group.Location
		newResource.Name = *group.Name
		newResource.Identifier = *group.ID
	}

	newCluster := r.immutableRender(newResource, immutable)
	return newCluster, newResource, nil
}

func ( r * ResourceGroup ) Actual ( immutable * cluster . Cluster ) ( * cluster . Cluster , cloud . Resource , error ) { logger . Debug ( " " ) newResource := & ResourceGroup { Shared : Shared { Name : r . Name , Tags : r . Tags , Identifier : immutable . ProviderConfig ( ) . GroupIdentifier , } , Location : r . Location , } if r . Identifier != " " { group , err := Sdk . ResourceGroup . Get ( immutable . Name ) if err != nil { return nil , nil , err } newResource . Location = * group . Location newResource . Name = * group . Name newResource . Identifier = * group . ID } newCluster := r . immutableRender ( newResource , immutable ) return newCluster , newResource , nil }

// Actual returns the actual resource group in Azure if it exists.

Actual returns the actual resource group in Azure if it exists .


func (r *ResourceGroup) Expected(immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("resourcegroup.Expected")
	newResource := &ResourceGroup{
		Shared: Shared{
			Name:       immutable.Name,
			Tags:       r.Tags,
			Identifier: immutable.ProviderConfig().GroupIdentifier,
		},
		Location: immutable.ProviderConfig().Location,
	}
	newCluster := r.immutableRender(newResource, immutable)
	return newCluster, newResource, nil
}

func ( r * ResourceGroup ) Expected ( immutable * cluster . Cluster ) ( * cluster . Cluster , cloud . Resource , error ) { logger . Debug ( " " ) newResource := & ResourceGroup { Shared : Shared { Name : immutable . Name , Tags : r . Tags , Identifier : immutable . ProviderConfig ( ) . GroupIdentifier , } , Location : immutable . ProviderConfig ( ) . Location , } newCluster := r . immutableRender ( newResource , immutable ) return newCluster , newResource , nil }

// Expected will return the expected resource group as it would be defined in Azure


func CreateCmd() *cobra.Command {
	var co = &cli.CreateOptions{}
	var createCmd = &cobra.Command{
		Use:   "create [NAME] [-p|--profile PROFILENAME] [-c|--cloudid CLOUDID]",
		Short: "Create a Kubicorn API model from a profile",
		Long: `Use this command to create a Kubicorn API model in a defined state store.

	This command will create a cluster API model as a YAML manifest in a state store.
	Once the API model has been created, a user can optionally change the model to their liking.
	After a model is defined and configured properly, the user can then apply the model.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch len(args) {
			case 0:
				co.Name = viper.GetString(keyKubicornName)
				if co.Name == "" {
					co.Name = namer.RandomName()
				}
			case 1:
				co.Name = args[0]
			default:
				logger.Critical("Too many arguments.")
				os.Exit(1)
			}

			if err := RunCreate(co); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}

		},
	}

	fs := createCmd.Flags()

	bindCommonStateStoreFlags(&co.StateStoreOptions, fs)
	bindCommonAwsFlags(&co.AwsOptions, fs)

	fs.StringVarP(&co.Profile, keyProfile, "p", viper.GetString(keyProfile), descProfile)
	fs.StringVarP(&co.CloudID, keyCloudID, "c", viper.GetString(keyCloudID), descCloudID)
	fs.StringVar(&co.KubeConfigLocalFile, keyKubeConfigLocalFile, viper.GetString(keyKubeConfigLocalFile), descKubeConfigLocalFile)
	fs.StringArrayVarP(&co.Set, keySet, "C", viper.GetStringSlice(keySet), descSet)
	fs.StringArrayVarP(&co.MasterSet, keyMasterSet, "M", viper.GetStringSlice(keyMasterSet), descMasterSet)
	fs.StringArrayVarP(&co.NodeSet, keyNodeSet, "N", viper.GetStringSlice(keyNodeSet), descNodeSet)
	fs.StringVarP(&co.GitRemote, keyGitConfig, "g", viper.GetString(keyGitConfig), descGitConfig)
	fs.StringArrayVar(&co.AwsOptions.PolicyAttachments, keyPolicyAttachments, co.AwsOptions.PolicyAttachments, descPolicyAttachments)

	flagApplyAnnotations(createCmd, "profile", "__kubicorn_parse_profiles")
	flagApplyAnnotations(createCmd, "cloudid", "__kubicorn_parse_cloudid")

	createCmd.SetUsageTemplate(cli.UsageTemplate)

	return createCmd
}


func NewUbuntuCluster(name string) *cluster.Cluster {

	controlPlaneProviderConfig := &cluster.ControlPlaneProviderConfig{
		Cloud:    cluster.CloudAzure,
		Location: "eastus",
		SSH: &cluster.SSH{
			PublicKeyPath: "~/.ssh/id_rsa.pub",
			User:          "root",
		},
		KubernetesAPI: &cluster.KubernetesAPI{
			Port: "443",
		},
		Values: &cluster.Values{
			ItemMap: map[string]string{
				"INJECTEDTOKEN": kubeadm.GetRandomToken(),
			},
		},
	}
	machineSetsProviderConfigs := []*cluster.MachineProviderConfig{
		{
			ServerPool: &cluster.ServerPool{
				Type:             cluster.ServerPoolTypeMaster,
				Name:             fmt.Sprintf("%s-master", name),
				MaxCount:         1,
				Image:            "UbuntuServer",
				Size:             "Standard_DS3_v2 ",
				BootstrapScripts: []string{},
				Firewalls: []*cluster.Firewall{
					{
						Name: fmt.Sprintf("%s-master", name),
						IngressRules: []*cluster.IngressRule{
							{
								IngressToPort:   "22",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "tcp",
							},
							{
								IngressToPort:   "443",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "tcp",
							},
							{
								IngressToPort:   "1194",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "udp",
							},
						},
						EgressRules: []*cluster.EgressRule{
							{
								EgressToPort:      "all", // By default all egress from VM
								EgressDestination: "0.0.0.0/0",
								EgressProtocol:    "tcp",
							},
							{
								EgressToPort:      "all", // By default all egress from VM
								EgressDestination: "0.0.0.0/0",
								EgressProtocol:    "udp",
							},
						},
					},
				},
			},
		},
		{
			ServerPool: &cluster.ServerPool{
				Type:             cluster.ServerPoolTypeNode,
				Name:             fmt.Sprintf("%s-node", name),
				MaxCount:         1,
				Image:            "UbuntuServer",
				Size:             "Standard_DS3_v2 ",
				BootstrapScripts: []string{},
				Firewalls: []*cluster.Firewall{
					{
						Name: fmt.Sprintf("%s-node", name),
						IngressRules: []*cluster.IngressRule{
							{
								IngressToPort:   "22",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "tcp",
							},
							{
								IngressToPort:   "1194",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "udp",
							},
						},
						EgressRules: []*cluster.EgressRule{
							{
								EgressToPort:      "all", // By default all egress from VM
								EgressDestination: "0.0.0.0/0",
								EgressProtocol:    "tcp",
							},
							{
								EgressToPort:      "all", // By default all egress from VM
								EgressDestination: "0.0.0.0/0",
								EgressProtocol:    "udp",
							},
						},
					},
				},
			},
		},
	}
	c := cluster.NewCluster(name)
	c.SetProviderConfig(controlPlaneProviderConfig)
	c.NewMachineSetsFromProviderConfigs(machineSetsProviderConfigs)
	return c
}

func
NewUbuntuCluster
(
name
string
)
*
cluster
.
Cluster
{
controlPlaneProviderConfig
:=
&
cluster
.
ControlPlaneProviderConfig
{
Cloud
:
cluster
.
CloudAzure
,
Location
:
"
"
,
SSH
:
&
cluster
.
SSH
{
PublicKeyPath
:
"
"
,
User
:
"
"
,
}
,
KubernetesAPI
:
&
cluster
.
KubernetesAPI
{
Port
:
"
"
,
}
,
Values
:
&
cluster
.
Values
{
ItemMap
:
map
[
string
]
string
{
"
"
:
kubeadm
.
GetRandomToken
(
)
,
}
,
}
,
}
machineSetsProviderConfigs
:=
[
]
*
cluster
.
MachineProviderConfig
{
{
ServerPool
:
&
cluster
.
ServerPool
{
Type
:
cluster
.
ServerPoolTypeMaster
,
Name
:
fmt
.
Sprintf
(
"
"
,
name
)
,
MaxCount
:
1
,
Image
:
"
"
,
Size
:
"
"
,
BootstrapScripts
:
[
]
string
{
}
,
Firewalls
:
[
]
*
cluster
.
Firewall
{
{
Name
:
fmt
.
Sprintf
(
"
"
,
name
)
,
IngressRules
:
[
]
*
cluster
.
IngressRule
{
{
IngressToPort
:
"
"
,
IngressSource
:
"
"
,
IngressProtocol
:
"
"
,
}
,
{
IngressToPort
:
"
"
,
IngressSource
:
"
"
,
IngressProtocol
:
"
"
,
}
,
{
IngressToPort
:
"
"
,
IngressSource
:
"
"
,
IngressProtocol
:
"
"
,
}
,
}
,
EgressRules
:
[
]
*
cluster
.
EgressRule
{
{
EgressToPort
:
"
"
,
// By default all egress from VM
EgressDestination
:
"
"
,
EgressProtocol
:
"
"
,
}
,
{
EgressToPort
:
"
"
,
// By default all egress from VM
EgressDestination
:
"
"
,
EgressProtocol
:
"
"
,
}
,
}
,
}
,
}
,
}
,
}
,
{
ServerPool
:
&
cluster
.
ServerPool
{
Type
:
cluster
.
ServerPoolTypeNode
,
Name
:
fmt
.
Sprintf
(
"
"
,
name
)
,
MaxCount
:
1
,
Image
:
"
"
,
Size
:
"
"
,
BootstrapScripts
:
[
]
string
{
}
,
Firewalls
:
[
]
*
cluster
.
Firewall
{
{
Name
:
fmt
.
Sprintf
(
"
"
,
name
)
,
IngressRules
:
[
]
*
cluster
.
IngressRule
{
{
IngressToPort
:
"
"
,
IngressSource
:
"
"
,
IngressProtocol
:
"
"
,
}
,
{
IngressToPort
:
"
"
,
IngressSource
:
"
"
,
IngressProtocol
:
"
"
,
}
,
}
,
EgressRules
:
[
]
*
cluster
.
EgressRule
{
{
EgressToPort
:
"
"
,
// By default all egress from VM
EgressDestination
:
"
"
,
EgressProtocol
:
"
"
,
}
,
{
EgressToPort
:
"
"
,
// By default all egress from VM
EgressDestination
:
"
"
,
EgressProtocol
:
"
"
,
}
,
}
,
}
,
}
,
}
,
}
,
}
c
:=
cluster
.
NewCluster
(
name
)
c
.
SetProviderConfig
(
controlPlaneProviderConfig
)
c
.
NewMachineSetsFromProviderConfigs
(
machineSetsProviderConfigs
)
return
c
}

// NewUbuntuCluster creates a basic Azure cluster profile, to bootstrap Kubernetes.

NewUbuntuCluster creates a basic Azure cluster profile to bootstrap Kubernetes .


func (c *Cluster) ProviderConfig() *ControlPlaneProviderConfig {
	//providerConfig providerConfig
	raw := c.ClusterAPI.Spec.ProviderConfig
	providerConfig := &ControlPlaneProviderConfig{}
	err := json.Unmarshal([]byte(raw), providerConfig)
	if err != nil {
		logger.Critical("Unable to unmarshal provider config: %v", err)
	}
	return providerConfig
}

func
(
c
*
Cluster
)
ProviderConfig
(
)
*
ControlPlaneProviderConfig
{
//providerConfig providerConfig
raw
:=
c
.
ClusterAPI
.
Spec
.
ProviderConfig
providerConfig
:=
&
ControlPlaneProviderConfig
{
}
err
:=
json
.
Unmarshal
(
[
]
byte
(
raw
)
,
providerConfig
)
if
err
!=
{
logger
.
Critical
(
"
"
,
err
)
}
return
providerConfig
}

// ProviderConfig is a convenience method that will attempt
// to return a ControlPlaneProviderConfig for a cluster.
// This is useful for managing the legacy API in a clean way.
// This will ignore errors from json.Unmarshal and will simply
// return an empty config.

ProviderConfig is a convenience method that will attempt to return a ControlPlaneProviderConfig for a cluster . This is useful for managing the legacy API in a clean way . This will ignore errors from json . Unmarshal and will simply return an empty config .


func (c *Cluster) SetProviderConfig(config *ControlPlaneProviderConfig) error {
	bytes, err := json.Marshal(config)
	if err != nil {
		logger.Critical("Unable to marshal provider config: %v", err)
		return err
	}
	str := string(bytes)
	c.ClusterAPI.Spec.ProviderConfig = str
	return nil
}

func ( c * Cluster ) SetProviderConfig ( config * ControlPlaneProviderConfig ) error { bytes , err := json . Marshal ( config ) if err != nil { logger . Critical ( " " , err ) return err } str := string ( bytes ) c . ClusterAPI . Spec . ProviderConfig = str return nil }

// SetProviderConfig is a convenience method that will attempt
// to set a provider config on a particular cluster. Just like
// it's counterpart ProviderConfig this makes working with the legacy API much easier.

SetProviderConfig is a convenience method that will attempt to set a provider config on a particular cluster . Just like it s counterpart ProviderConfig this makes working with the legacy API much easier .


func (c *Cluster) MachineProviderConfigs() []*MachineProviderConfig {
	var providerConfigs []*MachineProviderConfig
	for _, machineSet := range c.MachineSets {
		raw := machineSet.Spec.Template.Spec.ProviderConfig
		providerConfig := &MachineProviderConfig{}
		err := json.Unmarshal([]byte(raw), providerConfig)
		if err != nil {
			logger.Critical("Unable to unmarshal provider config: %v", err)
		}
		providerConfigs = append(providerConfigs, providerConfig)
	}
	return providerConfigs
}

func ( c * Cluster ) MachineProviderConfigs ( ) [ ] * MachineProviderConfig { var providerConfigs [ ] * MachineProviderConfig for _ , machineSet := range c . MachineSets { raw := machineSet . Spec . Template . Spec . ProviderConfig providerConfig := & MachineProviderConfig { } err := json . Unmarshal ( [ ] byte ( raw ) , providerConfig ) if err != nil { logger . Critical ( " " , err ) } providerConfigs = append ( providerConfigs , providerConfig ) } return providerConfigs }

// MachineProviderConfigs will return all MachineProviderConfigs for a cluster


func (c *Cluster) SetMachineProviderConfigs(providerConfigs []*MachineProviderConfig) {
	for _, providerConfig := range providerConfigs {
		name := providerConfig.ServerPool.Name
		found := false
		for _, machineSet := range c.MachineSets {
			if machineSet.Name == name {
				//logger.Debug("Matched machine set to provider config: %s", name)
				bytes, err := json.Marshal(providerConfig)
				if err != nil {
					logger.Critical("unable to marshal machine provider config: %v")
					continue
				}
				str := string(bytes)
				machineSet.Spec.Template.Spec.ProviderConfig = str
				found = true
			}
		}

		// TODO
		// @kris-nova
		// Right now if we have a machine provider config and we can't match it
		// we log a warning and move on. We might want to change this to create
		// the machineSet moving forward..
		if !found {
			logger.Warning("Unable to match provider config to machine set: %s", name)
		}

	}

}

// SetMachineProviderConfig will attempt to match a provider config to a machine set
// on the "Name" field. If a match cannot be made we warn and move on.

SetMachineProviderConfig will attempt to match a provider config to a machine set on the Name field . If a match cannot be made we warn and move on .


func NewCluster(name string) *Cluster {
	return &Cluster{
		Name: name,
		ClusterAPI: &clusterv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name: name,
			},
			Spec: clusterv1.ClusterSpec{},
		},
		ControlPlane: &clusterv1.MachineSet{},
	}
}

func NewCluster ( name string ) * Cluster { return & Cluster { Name : name , ClusterAPI : & clusterv1 . Cluster { ObjectMeta : metav1 . ObjectMeta { Name : name , } , Spec : clusterv1 . ClusterSpec { } , } , ControlPlane : & clusterv1 . MachineSet { } , } }

// NewCluster will initialize a new Cluster


func DeployControllerCmd() *cobra.Command {
	var dco = &cli.DeployControllerOptions{}
	var deployControllerCmd = &cobra.Command{
		Use:   "deploycontroller <NAME>",
		Short: "Deploy a controller for a given cluster",
		Long: `Use this command to deploy a controller for a given cluster.

As long as a controller is defined, this will create the deployment and the namespace.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch len(args) {
			case 0:
				dco.Name = viper.GetString(keyKubicornName)
			case 1:
				dco.Name = args[0]
			default:
				logger.Critical("Too many arguments.")
				os.Exit(1)
			}

			if err := runDeployController(dco); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}

		},
	}

	fs := deployControllerCmd.Flags()

	bindCommonStateStoreFlags(&dco.StateStoreOptions, fs)
	bindCommonAwsFlags(&dco.AwsOptions, fs)

	fs.StringVar(&dco.GitRemote, keyGitConfig, viper.GetString(keyGitConfig), descGitConfig)

	return deployControllerCmd
}

// DeployControllerCmd represents the apply command


func NewRetrier(retries, sleepSeconds int, retryable Retryable) *Retrier {
	return &Retrier{
		retries:      retries,
		sleepSeconds: sleepSeconds,
		retryable:    retryable,
	}
}

func NewRetrier ( retries , sleepSeconds int , retryable Retryable ) * Retrier { return & Retrier { retries : retries , sleepSeconds : sleepSeconds , retryable : retryable , } }

// NewRetrier creates a new Retrier using given properties.

NewRetrier creates a new Retrier using given properties .


func (r *Retrier) RunRetry() error {
	// Start signal handler.
	sigHandler := signals.NewSignalHandler(10)
	go sigHandler.Register()

	finish := make(chan bool, 1)
	go func() {
		select {
		case <-finish:
			return
		case <-time.After(10 * time.Second):
			return
		default:
			for {
				if sigHandler.GetState() != 0 {
					logger.Critical("detected signal. retry failed.")
					os.Exit(1)
				}
			}
		}
	}()

	for i := 0; i < r.retries; i++ {
		err := r.retryable.Try()
		if err != nil {
			logger.Info("Retryable error: %v", err)
			time.Sleep(time.Duration(r.sleepSeconds) * time.Second)
			continue
		}
		finish <- true
		return nil
	}

	finish <- true
	return fmt.Errorf("unable to succeed at retry after %d attempts at %d seconds", r.retries, r.sleepSeconds)
}

func
(
r
*
Retrier
)
RunRetry
(
)
error
{
// Start signal handler.
sigHandler
:=
signals
.
NewSignalHandler
(
10
)
go
sigHandler
.
Register
(
)
finish
:=
make
(
chan
bool
,
1
)
go
func
(
)
{
select
{
case
<-
finish
:
return
case
<-
time
.
After
(
10
*
time
.
Second
)
:
return
default
:
for
{
if
sigHandler
.
GetState
(
)
!=
0
{
logger
.
Critical
(
"
"
)
os
.
Exit
(
1
)
}
}
}
}
(
)
for
i
:=
0
;
i
<
r
.
retries
;
i
++
{
err
:=
r
.
retryable
.
Try
(
)
if
err
!=
{
logger
.
Info
(
"
"
,
err
)
time
.
Sleep
(
time
.
Duration
(
r
.
sleepSeconds
)
*
time
.
Second
)
continue
}
finish
<-
true
return
}
finish
<-
true
return
fmt
.
Errorf
(
"
"
,
r
.
retries
,
r
.
sleepSeconds
)
}


func MustGenerateRandomBytes(length int) []byte {
	res, err := GenerateRandomBytes(length)

	if err != nil {
		panic("Could not generate random bytes")
	}

	return res
}

func MustGenerateRandomBytes ( length int ) [ ] byte { res , err := GenerateRandomBytes ( length ) if err != nil { panic ( " " ) } return res }

// MustGenerateRandomBytes generates random bytes or panics if it can't

MustGenerateRandomBytes generates random bytes or panics if it can t


func ExplainCmd() *cobra.Command {
	var exo = &cli.ExplainOptions{}

	var cmd = &cobra.Command{
		Use:   "explain",
		Short: "Explain cluster",
		Long:  `Output expected and actual state of the given cluster`,
		Run: func(cmd *cobra.Command, args []string) {
			switch len(args) {
			case 0:
				exo.Name = viper.GetString(keyKubicornName)
			case 1:
				exo.Name = args[0]
			default:
				logger.Critical("Too many arguments.")
				os.Exit(1)
			}

			if err := runExplain(exo); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}
		},
	}

	fs := cmd.Flags()

	bindCommonStateStoreFlags(&exo.StateStoreOptions, fs)
	bindCommonAwsFlags(&exo.AwsOptions, fs)

	fs.StringVarP(&exo.Output, keyOutput, "o", viper.GetString(keyOutput), descOutput)
	fs.StringVar(&exo.GitRemote, keyGitConfig, viper.GetString(keyGitConfig), descGitConfig)

	return cmd
}

// ExplainCmd represents the explain command


func TimeOrderedUUID() string {
	unixTime := uint32(time.Now().UTC().Unix())
	return fmt.Sprintf("%08x-%04x-%04x-%04x-%04x%08x",
		unixTime,
		rand.MustGenerateRandomBytes(2),
		rand.MustGenerateRandomBytes(2),
		rand.MustGenerateRandomBytes(2),
		rand.MustGenerateRandomBytes(2),
		rand.MustGenerateRandomBytes(4))
}

func TimeOrderedUUID ( ) string { unixTime := uint32 ( time . Now ( ) . UTC ( ) . Unix ( ) ) return fmt . Sprintf ( " " , unixTime , rand . MustGenerateRandomBytes ( 2 ) , rand . MustGenerateRandomBytes ( 2 ) , rand . MustGenerateRandomBytes ( 2 ) , rand . MustGenerateRandomBytes ( 2 ) , rand . MustGenerateRandomBytes ( 4 ) ) }

// TimeOrderedUUID generates a time ordered UUID. Top 32b are timestamp bottom 96b are random.

TimeOrderedUUID generates a time ordered UUID . Top 32b are timestamp bottom 96b are random .


func GetConfigCmd() *cobra.Command {
	var cro = &cli.GetConfigOptions{}
	var getConfigCmd = &cobra.Command{
		Use:   "getconfig <NAME>",
		Short: "Manage Kubernetes configuration",
		Long: `Use this command to pull a kubeconfig file from a cluster so you can use kubectl.

	This command will attempt to find a cluster, and append a local kubeconfig file with a kubeconfig `,
		Run: func(cmd *cobra.Command, args []string) {
			switch len(args) {
			case 0:
				cro.Name = viper.GetString(keyKubicornName)
			case 1:
				cro.Name = args[0]
			default:
				logger.Critical("Too many arguments.")
				os.Exit(1)
			}

			if err := runGetConfig(cro); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}

		},
	}

	fs := getConfigCmd.Flags()

	bindCommonStateStoreFlags(&cro.StateStoreOptions, fs)
	bindCommonAwsFlags(&cro.AwsOptions, fs)

	fs.StringVar(&cro.GitRemote, keyGitConfig, viper.GetString(keyGitConfig), descGitConfig)

	return getConfigCmd
}

// GetConfigCmd represents the apply command


func RunAnnotated(task Task, description string, symbol string, options ...interface{}) error {
	doneCh := make(chan bool)
	errCh := make(chan error)

	l := logger.Log
	t := DefaultTicker

	for _, o := range options {
		if value, ok := o.(logger.Logger); ok {
			l = value
		} else if value, ok := o.(*time.Ticker); ok {
			t = value
		}
	}

	go func() {
		errCh <- task()
	}()

	l(description)
	logActivity(symbol, l, t, doneCh)

	err := <-errCh
	doneCh <- true

	return err
}

func RunAnnotated ( task Task , description string , symbol string , options ... interface { } ) error { doneCh := make ( chan bool ) errCh := make ( chan error ) l := logger . Log t := DefaultTicker for _ , o := range options { if value , ok := o . ( logger . Logger ) ; ok { l = value } else if value , ok := o . ( * time . Ticker ) ; ok { t = value } } go func ( ) { errCh <- task ( ) } ( ) l ( description ) logActivity ( symbol , l , t , doneCh ) err := <- errCh doneCh <- true return err }

// RunAnnotated annotates a task with a description and a sequence of symbols indicating task activity until it terminates


func ListCmd() *cobra.Command {
	var lo = &cli.ListOptions{}
	var cmd = &cobra.Command{
		Use:   "list",
		Short: "List available states",
		Long:  `List the states available in the _state directory`,
		Run: func(cmd *cobra.Command, args []string) {
			if err := runList(lo); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}
		},
	}

	fs := cmd.Flags()

	bindCommonStateStoreFlags(&lo.StateStoreOptions, fs)
	bindCommonAwsFlags(&lo.AwsOptions, fs)

	fs.BoolVarP(&noHeaders, keyNoHeaders, "n", viper.GetBool(keyNoHeaders), desNoHeaders)

	return cmd
}


func NewUbuntuCluster(name string) *cluster.Cluster {

	controlPlaneProviderConfig := &cluster.ControlPlaneProviderConfig{
		Cloud: cluster.CloudPacket,
		Project: &cluster.Project{
			Name: fmt.Sprintf("kubicorn-%s", name),
		},
		Location: "ewr1",
		SSH: &cluster.SSH{
			PublicKeyPath: "~/.ssh/id_rsa.pub",
			User:          "root",
		},
		KubernetesAPI: &cluster.KubernetesAPI{
			Port: "443",
		},
		Values: &cluster.Values{
			ItemMap: map[string]string{
				"INJECTEDTOKEN": kubeadm.GetRandomToken(),
			},
		},
	}
	machineSetsProviderConfigs := []*cluster.MachineProviderConfig{
		{
			ServerPool: &cluster.ServerPool{
				Type:     cluster.ServerPoolTypeMaster,
				Name:     fmt.Sprintf("%s.master", name),
				MaxCount: 1,
				MinCount: 1,
				Image:    "ubuntu_16_04",
				Size:     "baremetal_1",
				BootstrapScripts: []string{
					"bootstrap/packet_k8s_ubuntu_16.04_master.sh",
				},
			},
		},
		{
			ServerPool: &cluster.ServerPool{
				Type:     cluster.ServerPoolTypeNode,
				Name:     fmt.Sprintf("%s.node", name),
				MaxCount: 1,
				MinCount: 1,
				Image:    "ubuntu_16_04",
				Size:     "baremetal_2",
				BootstrapScripts: []string{
					"bootstrap/packet_k8s_ubuntu_16.04_node.sh",
				},
			},
		},
	}
	c := cluster.NewCluster(name)
	c.SetProviderConfig(controlPlaneProviderConfig)
	c.NewMachineSetsFromProviderConfigs(machineSetsProviderConfigs)
	return c
}

func NewUbuntuCluster ( name string ) * cluster . Cluster { controlPlaneProviderConfig := & cluster . ControlPlaneProviderConfig { Cloud : cluster . CloudPacket , Project : & cluster . Project { Name : fmt . Sprintf ( " " , name ) , } , Location : " " , SSH : & cluster . SSH { PublicKeyPath : " " , User : " " , } , KubernetesAPI : & cluster . KubernetesAPI { Port : " " , } , Values : & cluster . Values { ItemMap : map [ string ] string { " " : kubeadm . GetRandomToken ( ) , } , } , } machineSetsProviderConfigs := [ ] * cluster . MachineProviderConfig { { ServerPool : & cluster . ServerPool { Type : cluster . ServerPoolTypeMaster , Name : fmt . Sprintf ( " " , name ) , MaxCount : 1 , MinCount : 1 , Image : " " , Size : " " , BootstrapScripts : [ ] string { " " , } , } , } , { ServerPool : & cluster . ServerPool { Type : cluster . ServerPoolTypeNode , Name : fmt . Sprintf ( " " , name ) , MaxCount : 1 , MinCount : 1 , Image : " " , Size : " " , BootstrapScripts : [ ] string { " " , } , } , } , } c := cluster . NewCluster ( name ) c . SetProviderConfig ( controlPlaneProviderConfig ) c . NewMachineSetsFromProviderConfigs ( machineSetsProviderConfigs ) return c }

// NewUbuntuCluster creates a simple Ubuntu Amazon cluster


func EditCmd() *cobra.Command {
	var eo = &cli.EditOptions{}
	var editCmd = &cobra.Command{
		Use:   "edit <NAME>",
		Short: "Edit a cluster state",
		Long:  `Use this command to edit a state.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch len(args) {
			case 0:
				eo.Name = viper.GetString(keyKubicornName)
			case 1:
				eo.Name = args[0]
			default:
				logger.Critical("Too many arguments.")
				os.Exit(1)
			}

			if err := runEdit(eo); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}

		},
	}

	fs := editCmd.Flags()

	bindCommonStateStoreFlags(&eo.StateStoreOptions, fs)
	bindCommonAwsFlags(&eo.AwsOptions, fs)

	fs.StringVarP(&eo.Editor, keyEditor, "e", viper.GetString(keyEditor), descEditor)
	fs.StringVar(&eo.GitRemote, keyGitConfig, viper.GetString(keyGitConfig), descGitConfig)

	return editCmd
}

func
EditCmd
(
)
*
cobra
.
Command
{
var
eo
=
&
cli
.
EditOptions
{
}
var
editCmd
=
&
cobra
.
Command
{
Use
:
"
"
,
Short
:
"
"
,
Long
:
`Use this command to edit a state.`
,
Run
:
func
(
cmd
*
cobra
.
Command
,
args
[
]
string
)
{
switch
len
(
args
)
{
case
0
:
eo
.
Name
=
viper
.
GetString
(
keyKubicornName
)
case
1
:
eo
.
Name
=
args
[
0
]
default
:
logger
.
Critical
(
"
"
)
os
.
Exit
(
1
)
}
if
err
:=
runEdit
(
eo
)
;
err
!=
{
logger
.
Critical
(
err
.
Error
(
)
)
os
.
Exit
(
1
)
}
}
,
}
fs
:=
editCmd
.
Flags
(
)
bindCommonStateStoreFlags
(
&
eo
.
StateStoreOptions
,
fs
)
bindCommonAwsFlags
(
&
eo
.
AwsOptions
,
fs
)
fs
.
StringVarP
(
&
eo
.
Editor
,
keyEditor
,
"
"
,
viper
.
GetString
(
keyEditor
)
,
descEditor
)
fs
.
StringVar
(
&
eo
.
GitRemote
,
keyGitConfig
,
viper
.
GetString
(
keyGitConfig
)
,
descGitConfig
)
return
editCmd
}


func (k *Keyring) RemoveKey(key ssh.PublicKey) error {
	return k.Agent.Remove(key)
}

func ( k * Keyring ) RemoveKey ( key ssh . PublicKey ) error { return k . Agent . Remove ( key ) }

// RemoveKey removes an existing key from keyring


func (k *Keyring) RemoveKeyUsingFile(pubkey string) error {
	p, err := ioutil.ReadFile(pubkey)
	if err != nil {
		return err
	}

	key, _, _, _, _ := ssh.ParseAuthorizedKey(p)
	if err != nil {
		return err
	}

	return k.RemoveKey(key)
}

func ( k * Keyring ) RemoveKeyUsingFile ( pubkey string ) error { p , err := ioutil . ReadFile ( pubkey ) if err != nil { return err } key , _ , _ , _ , _ := ssh . ParseAuthorizedKey ( p ) if err != nil { return err } return k . RemoveKey ( key ) }

// RemoveKeyUsingFile removes an existing key from keyring given a file


func (r *Firewall) Actual(immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("firewall.Actual")

	newResource := defaultFirewallStruct()
	// Digital Firewalls.Get requires firewall ID, which we will not always have.thats why using List.
	firewalls, _, err := Sdk.Client.Firewalls.List(context.TODO(), &godo.ListOptions{})
	if err != nil {
		return nil, nil, fmt.Errorf("failed to get firwalls info")
	}
	for _, firewall := range firewalls {
		if firewall.Name == r.Name { // In digitalOcean Firwall names are unique.
			// gotcha get all details from this firewall and populate actual.
			firewallBytes, err := json.Marshal(firewall)
			if err != nil {
				return nil, nil, fmt.Errorf("failed to marshal DO firewall details err: %v", err)
			}
			if err := json.Unmarshal(firewallBytes, newResource); err != nil {
				return nil, nil, fmt.Errorf("failed to unmarhal DO firewall details err: %v", err)
			}
			// hack: DO api doesn't take "0" as portRange, but returns "0" for port range in firewall.List.
			for i := 0; i < len(newResource.OutboundRules); i++ {
				if newResource.OutboundRules[i].PortRange == "0" {
					newResource.OutboundRules[i].PortRange = "all"
				}
			}
			for i := 0; i < len(newResource.InboundRules); i++ {
				if newResource.InboundRules[i].PortRange == "0" {
					newResource.InboundRules[i].PortRange = "all"
				}
			}
		}
	}

	newCluster := r.immutableRender(newResource, immutable)
	return newCluster, newResource, nil
}

// Actual calls DO firewall Api and returns the actual state of firewall in the cloud.

Actual calls DO firewall Api and returns the actual state of firewall in the cloud .


func (r *Firewall) Expected(immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("firewall.Expected")
	newResource := &Firewall{
		Shared: Shared{
			Name:    r.Name,
			CloudID: r.ServerPool.Identifier,
		},
		InboundRules:  r.InboundRules,
		OutboundRules: r.OutboundRules,
		DropletIDs:    r.DropletIDs,
		Tags:          r.Tags,
		FirewallID:    r.FirewallID,
		Status:        r.Status,
		Created:       r.Created,
	}

	//logger.Info("Expected firewall returned is %+v", immutable)
	newCluster := r.immutableRender(newResource, immutable)
	return newCluster, newResource, nil

}

// Expected returns the Firewall structure of what is Expected.

Expected returns the Firewall structure of what is Expected .


func (r *Firewall) Apply(actual, expected cloud.Resource, immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("firewall.Apply")
	expectedResource := expected.(*Firewall)
	actualResource := actual.(*Firewall)

	isEqual, err := compare.IsEqual(actualResource, expectedResource)
	if err != nil {
		return nil, nil, err
	}
	if isEqual {
		return immutable, expected, nil
	}

	firewallRequest := godo.FirewallRequest{
		Name:          expectedResource.Name,
		InboundRules:  convertInRuleType(expectedResource.InboundRules),
		OutboundRules: convertOutRuleType(expectedResource.OutboundRules),
		DropletIDs:    expectedResource.DropletIDs,
		Tags:          expectedResource.Tags,
	}

	// Make sure Droplets are fully created before applying a firewall
	machineProviderConfigs := immutable.MachineProviderConfigs()
	for _, machineProviderConfig := range machineProviderConfigs {
		for i := 0; i <= TagsGetAttempts; i++ {
			active := true
			droplets, _, err := Sdk.Client.Droplets.ListByTag(context.TODO(), machineProviderConfig.ServerPool.Name, &godo.ListOptions{})
			if err != nil {
				logger.Debug("Hanging for droplets to get created.. (%v)", err)
				time.Sleep(time.Duration(TagsGetTimeout) * time.Second)
				continue
			}
			if len(droplets) == 0 {
				continue
			}
			for _, d := range droplets {
				if d.Status != "active" {
					active = false
					break
				}
			}
			if !active {
				logger.Debug("Waiting for droplets to become active..")
				time.Sleep(time.Duration(TagsGetTimeout) * time.Second)
				continue
			}
			break
		}
	}

	firewall, _, err := Sdk.Client.Firewalls.Create(context.TODO(), &firewallRequest)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to create the firewall err: %v", err)
	}
	logger.Success("Created Firewall [%s]", firewall.ID)
	newResource := &Firewall{
		Shared: Shared{
			CloudID: firewall.ID,
			Name:    r.Name,
			Tags:    r.Tags,
		},
		DropletIDs:    r.DropletIDs,
		FirewallID:    firewall.ID,
		InboundRules:  r.InboundRules,
		OutboundRules: r.OutboundRules,
		Created:       r.Created,
	}

	newCluster := r.immutableRender(newResource, immutable)
	return newCluster, newResource, nil
}

// Apply will compare the actual and expected firewall config, if needed it will create the firewall.

Apply will compare the actual and expected firewall config if needed it will create the firewall .


func (r *Firewall) Delete(actual cloud.Resource, immutable *cluster.Cluster) (*cluster.Cluster, cloud.Resource, error) {
	logger.Debug("firewall.Delete")
	deleteResource, ok := actual.(*Firewall)
	if !ok {
		return nil, nil, fmt.Errorf("failed to type convert actual Firewall type ")
	}
	if deleteResource.Name == "" {
		return immutable, nil, nil
		return nil, nil, fmt.Errorf("Unable to delete firewall resource without Name [%s]", deleteResource.Name)
	}
	if _, err := Sdk.Client.Firewalls.Delete(context.TODO(), deleteResource.FirewallID); err != nil {
		return nil, nil, fmt.Errorf("failed to delete firewall [%s] err: %v", deleteResource.Name, err)
	}
	logger.Success("Deleted firewall [%s]", deleteResource.FirewallID)

	newResource := &Firewall{
		Shared: Shared{
			Name: r.Name,
			Tags: r.Tags,
		},
		InboundRules:  r.InboundRules,
		OutboundRules: r.OutboundRules,
		Created:       r.Created,
	}

	newCluster := r.immutableRender(newResource, immutable)
	return newCluster, newResource, nil
}

func ( r * Firewall ) Delete ( actual cloud . Resource , immutable * cluster . Cluster ) ( * cluster . Cluster , cloud . Resource , error ) { logger . Debug ( " " ) deleteResource , ok := actual . ( * Firewall ) if ! ok { return nil , nil , fmt . Errorf ( " " ) } if deleteResource . Name == " " { return immutable , nil , nil return nil , nil , fmt . Errorf ( " " , deleteResource . Name ) } if _ , err := Sdk . Client . Firewalls . Delete ( context . TODO ( ) , deleteResource . FirewallID ) ; err != nil { return nil , nil , fmt . Errorf ( " " , deleteResource . Name , err ) } logger . Success ( " " , deleteResource . FirewallID ) newResource := & Firewall { Shared : Shared { Name : r . Name , Tags : r . Tags , } , InboundRules : r . InboundRules , OutboundRules : r . OutboundRules , Created : r . Created , } newCluster := r . immutableRender ( newResource , immutable ) return newCluster , newResource , nil }


func DeleteCmd() *cobra.Command {
	var do = &cli.DeleteOptions{}
	var deleteCmd = &cobra.Command{
		Use:   "delete <NAME>",
		Short: "Delete a Kubernetes cluster",
		Long: `Use this command to delete cloud resources.

	This command will attempt to build the resource graph based on an API model.
	Once the graph is built, the delete will attempt to delete the resources from the cloud.
	After the delete is complete, the state store will be left in tact and could potentially be applied later.

	To delete the resource AND the API model in the state store, use --purge.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch len(args) {
			case 0:
				do.Name = viper.GetString(keyKubicornName)
			case 1:
				do.Name = args[0]
			default:
				logger.Critical("Too many arguments.")
				os.Exit(1)
			}

			if err := runDelete(do); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}

		},
	}

	fs := deleteCmd.Flags()

	bindCommonStateStoreFlags(&do.StateStoreOptions, fs)
	bindCommonAwsFlags(&do.AwsOptions, fs)

	fs.StringVar(&do.AwsProfile, keyAwsProfile, viper.GetString(keyAwsProfile), descAwsProfile)
	fs.StringVar(&do.GitRemote, keyGitConfig, viper.GetString(keyGitConfig), descGitConfig)
	fs.BoolVarP(&do.Purge, keyPurge, "p", viper.GetBool(keyPurge), descPurge)

	return deleteCmd
}

// DeleteCmd represents the delete command


func (options Options) NewStateStore() (state.ClusterStorer, error) {
	var stateStore state.ClusterStorer

	switch options.StateStore {
	case "fs":
		logger.Info("Selected [fs] state store")
		stateStore = fs.NewFileSystemStore(&fs.FileSystemStoreOptions{
			BasePath:    options.StateStorePath,
			ClusterName: options.Name,
		})
	case "crd":
		logger.Info("Selected [crd] state store")
		stateStore = crd.NewCRDStore(&crd.CRDStoreOptions{
			BasePath:    options.StateStorePath,
			ClusterName: options.Name,
		})
	case "git":
		logger.Info("Selected [git] state store")
		if options.GitRemote == "" {
			return nil, errors.New("empty GitRemote url. Must specify the link to the remote git repo")
		}
		user, _ := gg.Global("user.name")
		email, _ := gg.Email()

		stateStore = git.NewJSONGitStore(&git.JSONGitStoreOptions{
			BasePath:    options.StateStorePath,
			ClusterName: options.Name,
			CommitConfig: &git.JSONGitCommitConfig{
				Name:   user,
				Email:  email,
				Remote: options.GitRemote,
			},
		})
	case "jsonfs":
		logger.Info("Selected [jsonfs] state store")
		stateStore = jsonfs.NewJSONFileSystemStore(&jsonfs.JSONFileSystemStoreOptions{
			BasePath:    options.StateStorePath,
			ClusterName: options.Name,
		})
	case "s3":
		logger.Info("Selected [s3] state store")
		client, err := minio.New(options.BucketEndpointURL, options.S3AccessKey, options.S3SecretKey, options.BucketSSL)
		if err != nil {
			return nil, err
		}
		stateStore = s3.NewJSONFS3Store(&s3.JSONS3StoreOptions{
			BasePath:    options.StateStorePath,
			ClusterName: options.Name,
			Client:      client,
			BucketOptions: &s3.S3BucketOptions{
				EndpointURL: options.BucketEndpointURL,
				BucketName:  options.BucketName,
			},
		})
	default:
		return nil, fmt.Errorf("state store [%s] has an invalid type [%s]", options.Name, options.StateStore)
	}

	return stateStore, nil
}

func ( options Options ) NewStateStore ( ) ( state . ClusterStorer , error ) { var stateStore state . ClusterStorer switch options . StateStore { case " " : logger . Info ( " " ) stateStore = fs . NewFileSystemStore ( & fs . FileSystemStoreOptions { BasePath : options . StateStorePath , ClusterName : options . Name , } ) case " " : logger . Info ( " " ) stateStore = crd . NewCRDStore ( & crd . CRDStoreOptions { BasePath : options . StateStorePath , ClusterName : options . Name , } ) case " " : logger . Info ( " " ) if options . GitRemote == " " { return nil , errors . New ( " " ) } user , _ := gg . Global ( " " ) email , _ := gg . Email ( ) stateStore = git . NewJSONGitStore ( & git . JSONGitStoreOptions { BasePath : options . StateStorePath , ClusterName : options . Name , CommitConfig : & git . JSONGitCommitConfig { Name : user , Email : email , Remote : options . GitRemote , } , } ) case " " : logger . Info ( " " ) stateStore = jsonfs . NewJSONFileSystemStore ( & jsonfs . JSONFileSystemStoreOptions { BasePath : options . StateStorePath , ClusterName : options . Name , } ) case " " : logger . Info ( " " ) client , err := minio . New ( options . BucketEndpointURL , options . S3AccessKey , options . S3SecretKey , options . BucketSSL ) if err != nil { return nil , err } stateStore = s3 . NewJSONFS3Store ( & s3 . JSONS3StoreOptions { BasePath : options . StateStorePath , ClusterName : options . Name , Client : client , BucketOptions : & s3 . S3BucketOptions { EndpointURL : options . BucketEndpointURL , BucketName : options . BucketName , } , } ) default : return nil , fmt . Errorf ( " " , options . Name , options . StateStore ) } return stateStore , nil }

// NewStateStore returns clusterStorer object based on type.

NewStateStore returns clusterStorer object based on type .


func (git *JSONGitStore) Commit(c *cluster.Cluster) error {
	if c == nil {
		return fmt.Errorf("Nil cluster spec")
	}
	bytes, err := json.Marshal(c)
	if err != nil {
		return err
	}

	//writes latest changes to git repo.
	git.Write(state.ClusterJSONFile, bytes)

	//commits the changes
	r, err := g.NewFilesystemRepository(state.ClusterJSONFile)
	if err != nil {
		return err
	}

	// Add a new remote, with the default fetch refspec
	_, err = r.CreateRemote(&config.RemoteConfig{
		Name: git.ClusterName,
		URL:  git.options.CommitConfig.Remote,
	})
	_, err = r.Commits()
	if err != nil {
		return err
	}
	return nil
}

//Performs a git 'commit' and 'push' of the current cluster changes.

Performs a git commit and push of the current cluster changes .


func ApplyCmd() *cobra.Command {
	var ao = &cli.ApplyOptions{}
	var applyCmd = &cobra.Command{
		Use:   "apply <NAME>",
		Short: "Apply a cluster resource to a cloud",
		Long: `Use this command to apply an API model in a cloud.

	This command will attempt to find an API model in a defined state store, and then apply any changes needed directly to a cloud.
	The apply will run once, and ultimately time out if something goes wrong.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch len(args) {
			case 0:
				ao.Name = viper.GetString(keyKubicornName)
			case 1:
				ao.Name = args[0]
			default:
				logger.Critical("Too many arguments.")
				os.Exit(1)
			}

			if err := runApply(ao); err != nil {
				logger.Critical(err.Error())
				os.Exit(1)
			}
		},
	}

	fs := applyCmd.Flags()

	bindCommonStateStoreFlags(&ao.StateStoreOptions, fs)
	bindCommonAwsFlags(&ao.AwsOptions, fs)

	fs.StringArrayVarP(&ao.Set, keyKubicornSet, "e", viper.GetStringSlice(keyKubicornSet), descSet)
	fs.StringVar(&ao.AwsProfile, keyAwsProfile, viper.GetString(keyAwsProfile), descAwsProfile)
	fs.StringVar(&ao.GitRemote, keyGitConfig, viper.GetString(keyGitConfig), descGitConfig)

	return applyCmd
}

// ApplyCmd represents the apply command


func ExpandPath(path string) string {
	switch path {
	case ".":
		wd, err := os.Getwd()
		if err != nil {
			logger.Critical("Unable to get current working directory: %v", err)
			return ""
		}
		path = wd
	case "~":
		homeVar := os.Getenv("HOME")
		if homeVar == "" {
			homeUser, err := user.Current()
			if err != nil {
				logger.Critical("Unable to use user.Current() for user. Maybe a cross compile issue: %v", err)
				return ""
			}
			path = homeUser.HomeDir
		}
	}

	return path
}

func ExpandPath ( path string ) string { switch path { case " " : wd , err := os . Getwd ( ) if err != nil { logger . Critical ( " " , err ) return " " } path = wd case " " : homeVar := os . Getenv ( " " ) if homeVar == " " { homeUser , err := user . Current ( ) if err != nil { logger . Critical ( " " , err ) return " " } path = homeUser . HomeDir } } return path }

// ExpandPath returns working directory path


func CompletionCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "completion",
		Short: "Generate completion code for bash and zsh shells.",
		Long: `completion is used to output completion code for bash and zsh shells.

	Before using completion features, you have to source completion code
	from your .profile. This is done by adding following line to one of above files:
		source <(kubicorn completion SHELL)
	Valid arguments for SHELL are: "bash" and "zsh".
	Notes:
	1) zsh completions requires zsh 5.2 or newer.

	2) macOS users have to install bash-completion framework to utilize
	completion features. This can be done using homebrew:
		brew install bash-completion
	Once installed, you must load bash_completion by adding following
	line to your .profile or .bashrc/.zshrc:
		source $(brew --prefix)/etc/bash_completion`,
		RunE: func(cmd *cobra.Command, args []string) error {
			if logger.Fabulous {
				cmd.SetOutput(logger.FabulousWriter)
			}

			if viper.GetString(keyTrueColor) != "" {
				cmd.SetOutput(logger.FabulousWriter)
			}

			switch len(args) {
			case 0:
				return fmt.Errorf("shell argument is not specified")
			default:
				switch args[0] {
				case "bash":
					return runBashGeneration()
				case "zsh":
					return runZshGeneration()
				default:
					return fmt.Errorf("invalid shell argument")
				}
			}
		},
	}
}

// CompletionCmd represents the completion command


func AdoptCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "adopt",
		Short: "Adopt a Kubernetes cluster into a Kubicorn state store",
		Long: `Use this command to audit and adopt a Kubernetes cluster into a Kubicorn state store.

	This command will query cloud resources and attempt to build a representation of the cluster in the Kubicorn API model.
	Once the cluster has been adopted, a user can manage and scale their Kubernetes cluster with Kubicorn.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("adopt called")
		},
	}
}

// AdoptCmd represents the adopt command


func StrEnvDef(env string, def string) string {
	val := os.Getenv(env)
	if val == "" {
		return def
	}
	return val
}

func StrEnvDef ( env string , def string ) string { val := os . Getenv ( env ) if val == " " { return def } return val }

// StrEnvDef get environment variable, or some default def

StrEnvDef get environment variable or some default def


func IntEnvDef(env string, def int) int {
	val := os.Getenv(env)
	if val == "" {
		return def
	}
	ival, err := strconv.Atoi(val)
	if err != nil {
		return def
	}
	return ival
}

func IntEnvDef ( env string , def int ) int { val := os . Getenv ( env ) if val == " " { return def } ival , err := strconv . Atoi ( val ) if err != nil { return def } return ival }

// IntEnvDef get environment variable, or some default def

IntEnvDef get environment variable or some default def


func BoolEnvDef(env string, def bool) bool {
	val := os.Getenv(env)
	if val == "" {
		return def
	}
	b, err := strconv.ParseBool(val)
	if err != nil {
		return def
	}
	return b
}

func BoolEnvDef ( env string , def bool ) bool { val := os . Getenv ( env ) if val == " " { return def } b , err := strconv . ParseBool ( val ) if err != nil { return def } return b }

// BoolEnvDef get environemnt variable and return bool.

BoolEnvDef get environemnt variable and return bool .


func readFromFS(sourcePath string) (string, error) {

	// If sourcePath starts with ~ we search for $HOME
	// and preppend it to the absolutePath overwriting the first character
	// TODO: Add Windows support
	if strings.HasPrefix(sourcePath, "~") {
		homeDir := os.Getenv("HOME")
		if homeDir == "" {
			return "", fmt.Errorf("Could not find $HOME")
		}
		sourcePath = filepath.Join(homeDir, sourcePath[1:])
	}

	bytes, err := ioutil.ReadFile(sourcePath)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

// readFromFS reads file from a local path and returns as string


func VersionCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "version",
		Short: "Verify Kubicorn version",
		Long: `Use this command to check the version of Kubicorn.

	This command will return the version of the Kubicorn binary.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("%s\n", version.GetVersionJSON())
		},
	}
}

// VersionCmd represents the version command


func NewSignalHandler(timeoutSeconds int) *Handler {
	signals := make(chan os.Signal)
	signal.Notify(signals, os.Interrupt, os.Kill)
	return &Handler{
		timeoutSeconds: timeoutSeconds,
		signals:        signals,
		signalReceived: 0,
	}
}

func NewSignalHandler ( timeoutSeconds int ) * Handler { signals := make ( chan os . Signal ) signal . Notify ( signals , os . Interrupt , os . Kill ) return & Handler { timeoutSeconds : timeoutSeconds , signals : signals , signalReceived : 0 , } }

// NewSignalHandler creates a new Handler using given properties.

NewSignalHandler creates a new Handler using given properties .


func (h *Handler) Register() {
	go func() {
		h.timer = time.NewTimer(time.Duration(h.timeoutSeconds) * time.Second)
		for {
			select {
			case s := <-h.signals:
				switch {
				case s == os.Interrupt:
					if h.signalReceived == 0 {
						h.signalReceived = 1
						logger.Debug("SIGINT Received")
						continue
					}
					h.signalReceived = signalTerminate
					debug.PrintStack()
					os.Exit(130)
					break
				case s == syscall.SIGQUIT:
					h.signalReceived = signalAbort
					break
				case s == syscall.SIGTERM:
					h.signalReceived = signalTerminate
					os.Exit(3)
					break
				}
			case <-h.timer.C:
				os.Exit(4)
				break
			}
		}

	}()
}

func ( h * Handler ) Register ( ) { go func ( ) { h . timer = time . NewTimer ( time . Duration ( h . timeoutSeconds ) * time . Second ) for { select { case s := <- h . signals : switch { case s == os . Interrupt : if h . signalReceived == 0 { h . signalReceived = 1 logger . Debug ( " " ) continue } h . signalReceived = signalTerminate debug . PrintStack ( ) os . Exit ( 130 ) break case s == syscall . SIGQUIT : h . signalReceived = signalAbort break case s == syscall . SIGTERM : h . signalReceived = signalTerminate os . Exit ( 3 ) break } case <- h . timer . C : os . Exit ( 4 ) break } } } ( ) }


func NewUbuntuCluster(name string) *cluster.Cluster {
	var (
		masterName = fmt.Sprintf("%s-master", name)
		nodeName   = fmt.Sprintf("%s-node", name)
	)
	controlPlaneProviderConfig := &cluster.ControlPlaneProviderConfig{
		Cloud:    cluster.CloudECS,
		Location: "nl-ams1",
		SSH: &cluster.SSH{
			PublicKeyPath: "~/.ssh/id_rsa.pub",
			User:          "ubuntu",
		},
		Values: &cluster.Values{
			ItemMap: map[string]string{
				"INJECTEDTOKEN": kubeadm.GetRandomToken(),
			},
		},
		KubernetesAPI: &cluster.KubernetesAPI{
			Port: "443",
		},
		Network: &cluster.Network{
			Type: cluster.NetworkTypePublic,
			InternetGW: &cluster.InternetGW{
				Name: "default",
			},
		},
	}
	machineSetsProviderConfigs := []*cluster.MachineProviderConfig{
		{
			ServerPool: &cluster.ServerPool{
				Type:     cluster.ServerPoolTypeMaster,
				Name:     masterName,
				MaxCount: 1,
				Image:    "GNU/Linux Ubuntu Server 16.04 Xenial Xerus x64",
				Size:     "e3standard.x3",
				BootstrapScripts: []string{
					"bootstrap/ecs_k8s_ubuntu_16.04_master.sh",
				},
				Subnets: []*cluster.Subnet{
					{
						Name: "internal",
						CIDR: "192.168.200.0/24",
					},
				},
				Firewalls: []*cluster.Firewall{
					{
						Name: masterName,
						IngressRules: []*cluster.IngressRule{
							{
								IngressFromPort: "22",
								IngressToPort:   "22",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "tcp",
							},
							{
								IngressFromPort: "443",
								IngressToPort:   "443",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "tcp",
							},
							{
								IngressSource: "192.168.200.0/24",
							},
						},
					},
				},
			},
		},
		{
			ServerPool: &cluster.ServerPool{
				Type:     cluster.ServerPoolTypeNode,
				Name:     nodeName,
				MaxCount: 2,
				Image:    "GNU/Linux Ubuntu Server 16.04 Xenial Xerus x64",
				Size:     "e3standard.x3",
				BootstrapScripts: []string{
					"bootstrap/ecs_k8s_ubuntu_16.04_node.sh",
				},
				Firewalls: []*cluster.Firewall{
					{
						Name: nodeName,
						IngressRules: []*cluster.IngressRule{
							{
								IngressFromPort: "22",
								IngressToPort:   "22",
								IngressSource:   "0.0.0.0/0",
								IngressProtocol: "tcp",
							},
							{
								IngressSource: "192.168.200.0/24",
							},
						},
					},
				},
			},
		},
	}
	c := cluster.NewCluster(name)
	c.SetProviderConfig(controlPlaneProviderConfig)
	c.NewMachineSetsFromProviderConfigs(machineSetsProviderConfigs)
	return c
}

func NewUbuntuCluster ( name string ) * cluster . Cluster { var ( masterName = fmt . Sprintf ( " " , name ) nodeName = fmt . Sprintf ( " " , name ) ) controlPlaneProviderConfig := & cluster . ControlPlaneProviderConfig { Cloud : cluster . CloudECS , Location : " " , SSH : & cluster . SSH { PublicKeyPath : " " , User : " " , } , Values : & cluster . Values { ItemMap : map [ string ] string { " " : kubeadm . GetRandomToken ( ) , } , } , KubernetesAPI : & cluster . KubernetesAPI { Port : " " , } , Network : & cluster . Network { Type : cluster . NetworkTypePublic , InternetGW : & cluster . InternetGW { Name : " " , } , } , } machineSetsProviderConfigs := [ ] * cluster . MachineProviderConfig { { ServerPool : & cluster . ServerPool { Type : cluster . ServerPoolTypeMaster , Name : masterName , MaxCount : 1 , Image : " " , Size : " " , BootstrapScripts : [ ] string { " " , } , Subnets : [ ] * cluster . Subnet { { Name : " " , CIDR : " " , } , } , Firewalls : [ ] * cluster . Firewall { { Name : masterName , IngressRules : [ ] * cluster . IngressRule { { IngressFromPort : " " , IngressToPort : " " , IngressSource : " " , IngressProtocol : " " , } , { IngressFromPort : " " , IngressToPort : " " , IngressSource : " " , IngressProtocol : " " , } , { IngressSource : " " , } , } , } , } , } , } , { ServerPool : & cluster . ServerPool { Type : cluster . ServerPoolTypeNode , Name : nodeName , MaxCount : 2 , Image : " " , Size : " " , BootstrapScripts : [ ] string { " " , } , Firewalls : [ ] * cluster . Firewall { { Name : nodeName , IngressRules : [ ] * cluster . IngressRule { { IngressFromPort : " " , IngressToPort : " " , IngressSource : " " , IngressProtocol : " " , } , { IngressSource : " " , } , } , } , } , } , } , } c := cluster . NewCluster ( name ) c . SetProviderConfig ( controlPlaneProviderConfig ) c . NewMachineSetsFromProviderConfigs ( machineSetsProviderConfigs ) return c }

// NewUbuntuCluster creates a simple Ubuntu Openstack cluster.

NewUbuntuCluster creates a simple Ubuntu Openstack cluster .


func (now *Now) BeginningOfHour() time.Time {
	y, m, d := now.Date()
	return time.Date(y, m, d, now.Time.Hour(), 0, 0, 0, now.Time.Location())
}

func ( now * Now ) BeginningOfHour ( ) time . Time { y , m , d := now . Date ( ) return time . Date ( y , m , d , now . Time . Hour ( ) , 0 , 0 , 0 , now . Time . Location ( ) ) }


func (now *Now) BeginningOfDay() time.Time {
	y, m, d := now.Date()
	return time.Date(y, m, d, 0, 0, 0, 0, now.Time.Location())
}

func ( now * Now ) BeginningOfDay ( ) time . Time { y , m , d := now . Date ( ) return time . Date ( y , m , d , 0 , 0 , 0 , 0 , now . Time . Location ( ) ) }


func (now *Now) BeginningOfWeek() time.Time {
	t := now.BeginningOfDay()
	weekday := int(t.Weekday())

	if WeekStartDay != time.Sunday {
		weekStartDayInt := int(WeekStartDay)

		if weekday < weekStartDayInt {
			weekday = weekday + 7 - weekStartDayInt
		} else {
			weekday = weekday - weekStartDayInt
		}
	}
	return t.AddDate(0, 0, -weekday)
}

func ( now * Now ) BeginningOfWeek ( ) time . Time { t := now . BeginningOfDay ( ) weekday := int ( t . Weekday ( ) ) if WeekStartDay != time . Sunday { weekStartDayInt := int ( WeekStartDay ) if weekday < weekStartDayInt { weekday = weekday + 7 - weekStartDayInt } else { weekday = weekday - weekStartDayInt } } return t . AddDate ( 0 , 0 , - weekday ) }


func (now *Now) BeginningOfMonth() time.Time {
	y, m, _ := now.Date()
	return time.Date(y, m, 1, 0, 0, 0, 0, now.Location())
}

func ( now * Now ) BeginningOfMonth ( ) time . Time { y , m , _ := now . Date ( ) return time . Date ( y , m , 1 , 0 , 0 , 0 , 0 , now . Location ( ) ) }


func (now *Now) BeginningOfQuarter() time.Time {
	month := now.BeginningOfMonth()
	offset := (int(month.Month()) - 1) % 3
	return month.AddDate(0, -offset, 0)
}

func ( now * Now ) BeginningOfQuarter ( ) time . Time { month := now . BeginningOfMonth ( ) offset := ( int ( month . Month ( ) ) - 1 ) % 3 return month . AddDate ( 0 , - offset , 0 ) }

// BeginningOfQuarter beginning of quarter


func (now *Now) BeginningOfYear() time.Time {
	y, _, _ := now.Date()
	return time.Date(y, time.January, 1, 0, 0, 0, 0, now.Location())
}

func ( now * Now ) BeginningOfYear ( ) time . Time { y , _ , _ := now . Date ( ) return time . Date ( y , time . January , 1 , 0 , 0 , 0 , 0 , now . Location ( ) ) }

// BeginningOfYear BeginningOfYear beginning of year


func (now *Now) EndOfMinute() time.Time {
	return now.BeginningOfMinute().Add(time.Minute - time.Nanosecond)
}

func ( now * Now ) EndOfMinute ( ) time . Time { return now . BeginningOfMinute ( ) . Add ( time . Minute - time . Nanosecond ) }


func (now *Now) EndOfHour() time.Time {
	return now.BeginningOfHour().Add(time.Hour - time.Nanosecond)
}

func ( now * Now ) EndOfHour ( ) time . Time { return now . BeginningOfHour ( ) . Add ( time . Hour - time . Nanosecond ) }


func (now *Now) EndOfDay() time.Time {
	y, m, d := now.Date()
	return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), now.Location())
}

func ( now * Now ) EndOfDay ( ) time . Time { y , m , d := now . Date ( ) return time . Date ( y , m , d , 23 , 59 , 59 , int ( time . Second - time . Nanosecond ) , now . Location ( ) ) }


func (now *Now) EndOfWeek() time.Time {
	return now.BeginningOfWeek().AddDate(0, 0, 7).Add(-time.Nanosecond)
}

func ( now * Now ) EndOfWeek ( ) time . Time { return now . BeginningOfWeek ( ) . AddDate ( 0 , 0 , 7 ) . Add ( - time . Nanosecond ) }


func (now *Now) EndOfMonth() time.Time {
	return now.BeginningOfMonth().AddDate(0, 1, 0).Add(-time.Nanosecond)
}

func ( now * Now ) EndOfMonth ( ) time . Time { return now . BeginningOfMonth ( ) . AddDate ( 0 , 1 , 0 ) . Add ( - time . Nanosecond ) }


func (now *Now) EndOfQuarter() time.Time {
	return now.BeginningOfQuarter().AddDate(0, 3, 0).Add(-time.Nanosecond)
}

func ( now * Now ) EndOfQuarter ( ) time . Time { return now . BeginningOfQuarter ( ) . AddDate ( 0 , 3 , 0 ) . Add ( - time . Nanosecond ) }


func (now *Now) EndOfYear() time.Time {
	return now.BeginningOfYear().AddDate(1, 0, 0).Add(-time.Nanosecond)
}

func ( now * Now ) EndOfYear ( ) time . Time { return now . BeginningOfYear ( ) . AddDate ( 1 , 0 , 0 ) . Add ( - time . Nanosecond ) }


func (now *Now) MustParse(strs ...string) (t time.Time) {
	t, err := now.Parse(strs...)
	if err != nil {
		panic(err)
	}
	return t
}

func ( now * Now ) MustParse ( strs ... string ) ( t time . Time ) { t , err := now . Parse ( strs ... ) if err != nil { panic ( err ) } return t }

// MustParse must parse string to time or it will panic


func (now *Now) Between(begin, end string) bool {
	beginTime := now.MustParse(begin)
	endTime := now.MustParse(end)
	return now.After(beginTime) && now.Before(endTime)
}

func ( now * Now ) Between ( begin , end string ) bool { beginTime := now . MustParse ( begin ) endTime := now . MustParse ( end ) return now . After ( beginTime ) && now . Before ( endTime ) }

// Between check time between the begin, end time or not

Between check time between the begin end time or not


func ParseInLocation(loc *time.Location, strs ...string) (time.Time, error) {
	return New(time.Now().In(loc)).Parse(strs...)
}

func ParseInLocation ( loc * time . Location , strs ... string ) ( time . Time , error ) { return New ( time . Now ( ) . In ( loc ) ) . Parse ( strs ... ) }

// ParseInLocation parse string to time in location


func MustParse(strs ...string) time.Time {
	return New(time.Now()).MustParse(strs...)
}

func MustParse ( strs ... string ) time . Time { return New ( time . Now ( ) ) . MustParse ( strs ... ) }

// MustParse must parse string to time or will panic


func MustParseInLocation(loc *time.Location, strs ...string) time.Time {
	return New(time.Now().In(loc)).MustParse(strs...)
}

func MustParseInLocation ( loc * time . Location , strs ... string ) time . Time { return New ( time . Now ( ) . In ( loc ) ) . MustParse ( strs ... ) }

// MustParseInLocation must parse string to time in location or will panic


func Between(time1, time2 string) bool {
	return New(time.Now()).Between(time1, time2)
}

func Between ( time1 , time2 string ) bool { return New ( time . Now ( ) ) . Between ( time1 , time2 ) }

// Between check now between the begin, end time or not

Between check now between the begin end time or not


func NewChannelMemoryBackend(size int) *ChannelMemoryBackend {
	backend := &ChannelMemoryBackend{
		maxSize:  size,
		incoming: make(chan *Record, 1024),
		events:   make(chan event),
	}
	backend.Start()
	return backend
}

func NewChannelMemoryBackend ( size int ) * ChannelMemoryBackend { backend := & ChannelMemoryBackend { maxSize : size , incoming : make ( chan * Record , 1024 ) , events : make ( chan event ) , } backend . Start ( ) return backend }

// NewChannelMemoryBackend creates a simple in-memory logging backend which
// utilizes a go channel for communication.
//
// Start will automatically be called by this function.

NewChannelMemoryBackend creates a simple in - memory logging backend which utilizes a go channel for communication . Start will automatically be called by this function .


func (b *ChannelMemoryBackend) Start() {
	b.mu.Lock()
	defer b.mu.Unlock()

	// Launch the goroutine unless it's already running.
	if b.running != true {
		b.running = true
		b.stopWg.Add(1)
		go b.process()
	}
}

// Start launches the internal goroutine which starts processing data from the
// input channel.

Start launches the internal goroutine which starts processing data from the input channel .


func (b *ChannelMemoryBackend) Flush() {
	b.flushWg.Add(1)
	b.events <- eventFlush
	b.flushWg.Wait()
}

func ( b * ChannelMemoryBackend ) Flush ( ) { b . flushWg . Add ( 1 ) b . events <- eventFlush b . flushWg . Wait ( ) }

// Flush waits until all records in the buffered channel have been processed.

Flush waits until all records in the buffered channel have been processed .


func (b *ChannelMemoryBackend) Stop() {
	b.mu.Lock()
	if b.running == true {
		b.running = false
		b.events <- eventStop
	}
	b.mu.Unlock()
	b.stopWg.Wait()
}

func ( b * ChannelMemoryBackend ) Stop ( ) { b . mu . Lock ( ) if b . running == true { b . running = false b . events <- eventStop } b . mu . Unlock ( ) b . stopWg . Wait ( ) }

// Stop signals the internal goroutine to exit and waits until it have.

Stop signals the internal goroutine to exit and waits until it have .


func (r *Record) Formatted(calldepth int) string {
	if r.formatted == "" {
		var buf bytes.Buffer
		r.formatter.Format(calldepth+1, r, &buf)
		r.formatted = buf.String()
	}
	return r.formatted
}

func ( r * Record ) Formatted ( calldepth int ) string { if r . formatted == " " { var buf bytes . Buffer r . formatter . Format ( calldepth + 1 , r , & buf ) r . formatted = buf . String ( ) } return r . formatted }

// Formatted returns the formatted log record string.

Formatted returns the formatted log record string .


func (r *Record) Message() string {
	if r.message == nil {
		// Redact the arguments that implements the Redactor interface
		for i, arg := range r.Args {
			if redactor, ok := arg.(Redactor); ok == true {
				r.Args[i] = redactor.Redacted()
			}
		}
		var buf bytes.Buffer
		if r.fmt != nil {
			fmt.Fprintf(&buf, *r.fmt, r.Args...)
		} else {
			// use Fprintln to make sure we always get space between arguments
			fmt.Fprintln(&buf, r.Args...)
			buf.Truncate(buf.Len() - 1) // strip newline
		}
		msg := buf.String()
		r.message = &msg
	}
	return *r.message
}

// Message returns the log record message.

Message returns the log record message .


func (l *Logger) SetBackend(backend LeveledBackend) {
	l.backend = backend
	l.haveBackend = true
}

func ( l * Logger ) SetBackend ( backend LeveledBackend ) { l . backend = backend l . haveBackend = true }

// SetBackend overrides any previously defined backend for this logger.

SetBackend overrides any previously defined backend for this logger .


func MustGetLogger(module string) *Logger {
	logger, err := GetLogger(module)
	if err != nil {
		panic("logger: " + module + ": " + err.Error())
	}
	return logger
}

func MustGetLogger ( module string ) * Logger { logger , err := GetLogger ( module ) if err != nil { panic ( " " + module + " " + err . Error ( ) ) } return logger }

// MustGetLogger is like GetLogger but panics if the logger can't be created.
// It simplifies safe initialization of a global logger for eg. a package.

MustGetLogger is like GetLogger but panics if the logger can t be created . It simplifies safe initialization of a global logger for eg . a package .


func Reset() {
	// TODO make a global Init() method to be less magic? or make it such that
	// if there's no backends at all configured, we could use some tricks to
	// automatically setup backends based if we have a TTY or not.
	sequenceNo = 0
	b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags))
	b.SetLevel(DEBUG, "")
	SetFormatter(DefaultFormatter)
	timeNow = time.Now
}

// Reset restores the internal state of the logging library.

Reset restores the internal state of the logging library .


func (l *Logger) IsEnabledFor(level Level) bool {
	return defaultBackend.IsEnabledFor(level, l.Module)
}

func ( l * Logger ) IsEnabledFor ( level Level ) bool { return defaultBackend . IsEnabledFor ( level , l . Module ) }

// IsEnabledFor returns true if the logger is enabled for the given level.

IsEnabledFor returns true if the logger is enabled for the given level .


func (l *Logger) Criticalf(format string, args ...interface{}) {
	l.log(CRITICAL, &format, args...)
}

func ( l * Logger ) Criticalf ( format string , args ... interface { } ) { l . log ( CRITICAL , & format , args ... ) }

// Criticalf logs a message using CRITICAL as log level.

Criticalf logs a message using CRITICAL as log level .


func (l *Logger) Warningf(format string, args ...interface{}) {
	l.log(WARNING, &format, args...)
}

func ( l * Logger ) Warningf ( format string , args ... interface { } ) { l . log ( WARNING , & format , args ... ) }

// Warningf logs a message using WARNING as log level.

Warningf logs a message using WARNING as log level .


func (l *Logger) Noticef(format string, args ...interface{}) {
	l.log(NOTICE, &format, args...)
}

func ( l * Logger ) Noticef ( format string , args ... interface { } ) { l . log ( NOTICE , & format , args ... ) }

// Noticef logs a message using NOTICE as log level.

Noticef logs a message using NOTICE as log level .


func (l *Logger) Infof(format string, args ...interface{}) {
	l.log(INFO, &format, args...)
}

func ( l * Logger ) Infof ( format string , args ... interface { } ) { l . log ( INFO , & format , args ... ) }

// Infof logs a message using INFO as log level.

Infof logs a message using INFO as log level .


func SetFormatter(f Formatter) {
	formatter.Lock()
	defer formatter.Unlock()
	formatter.def = f
}

func SetFormatter ( f Formatter ) { formatter . Lock ( ) defer formatter . Unlock ( ) formatter . def = f }

// SetFormatter sets the default formatter for all new backends. A backend will
// fetch this value once it is needed to format a record. Note that backends
// will cache the formatter after the first point. For now, make sure to set
// the formatter before logging.

SetFormatter sets the default formatter for all new backends . A backend will fetch this value once it is needed to format a record . Note that backends will cache the formatter after the first point . For now make sure to set the formatter before logging .


func MustStringFormatter(format string) Formatter {
	f, err := NewStringFormatter(format)
	if err != nil {
		panic("Failed to initialized string formatter: " + err.Error())
	}
	return f
}

func MustStringFormatter ( format string ) Formatter { f , err := NewStringFormatter ( format ) if err != nil { panic ( " " + err . Error ( ) ) } return f }

// MustStringFormatter is equivalent to NewStringFormatter with a call to panic
// on error.

MustStringFormatter is equivalent to NewStringFormatter with a call to panic on error .


func formatFuncName(v fmtVerb, f string) string {
	i := strings.LastIndex(f, "/")
	j := strings.Index(f[i+1:], ".")
	if j < 1 {
		return "???"
	}
	pkg, fun := f[:i+j+1], f[i+j+2:]
	switch v {
	case fmtVerbLongpkg:
		return pkg
	case fmtVerbShortpkg:
		return path.Base(pkg)
	case fmtVerbLongfunc:
		return fun
	case fmtVerbShortfunc:
		i = strings.LastIndex(fun, ".")
		return fun[i+1:]
	}
	panic("unexpected func formatter")
}

func formatFuncName ( v fmtVerb , f string ) string { i := strings . LastIndex ( f , " " ) j := strings . Index ( f [ i + 1 : ] , " " ) if j < 1 { return " " } pkg , fun := f [ : i + j + 1 ] , f [ i + j + 2 : ] switch v { case fmtVerbLongpkg : return pkg case fmtVerbShortpkg : return path . Base ( pkg ) case fmtVerbLongfunc : return fun case fmtVerbShortfunc : i = strings . LastIndex ( fun , " " ) return fun [ i + 1 : ] } panic ( " " ) }

// formatFuncName tries to extract certain part of the runtime formatted
// function name to some pre-defined variation.
//
// This function is known to not work properly if the package path or name
// contains a dot.

formatFuncName tries to extract certain part of the runtime formatted function name to some pre - defined variation . This function is known to not work properly if the package path or name contains a dot .


func (bf *backendFormatter) Log(level Level, calldepth int, r *Record) error {
	// Make a shallow copy of the record and replace any formatter
	r2 := *r
	r2.formatter = bf.f
	return bf.b.Log(level, calldepth+1, &r2)
}

// Log implements the Log function required by the Backend interface.

Log implements the Log function required by the Backend interface .


func LogLevel(level string) (Level, error) {
	for i, name := range levelNames {
		if strings.EqualFold(name, level) {
			return Level(i), nil
		}
	}
	return ERROR, ErrInvalidLogLevel
}

func LogLevel ( level string ) ( Level , error ) { for i , name := range levelNames { if strings . EqualFold ( name , level ) { return Level ( i ) , nil } } return ERROR , ErrInvalidLogLevel }

// LogLevel returns the log level from a string representation.

LogLevel returns the log level from a string representation .


func AddModuleLevel(backend Backend) LeveledBackend {
	var leveled LeveledBackend
	var ok bool
	if leveled, ok = backend.(LeveledBackend); !ok {
		leveled = &moduleLeveled{
			levels:  make(map[string]Level),
			backend: backend,
		}
	}
	return leveled
}

func AddModuleLevel ( backend Backend ) LeveledBackend { var leveled LeveledBackend var ok bool if leveled , ok = backend . ( LeveledBackend ) ; ! ok { leveled = & moduleLeveled { levels : make ( map [ string ] Level ) , backend : backend , } } return leveled }

// AddModuleLevel wraps a log backend with knobs to have different log levels
// for different modules.

AddModuleLevel wraps a log backend with knobs to have different log levels for different modules .


func (l *moduleLeveled) GetLevel(module string) Level {
	level, exists := l.levels[module]
	if exists == false {
		level, exists = l.levels[""]
		// no configuration exists, default to debug
		if exists == false {
			level = DEBUG
		}
	}
	return level
}

// GetLevel returns the log level for the given module.

GetLevel returns the log level for the given module .


func (l *moduleLeveled) SetLevel(level Level, module string) {
	l.levels[module] = level
}

func ( l * moduleLeveled ) SetLevel ( level Level , module string ) { l . levels [ module ] = level }

// SetLevel sets the log level for the given module.

SetLevel sets the log level for the given module .


func (l *moduleLeveled) IsEnabledFor(level Level, module string) bool {
	return level <= l.GetLevel(module)
}

func ( l * moduleLeveled ) IsEnabledFor ( level Level , module string ) bool { return level <= l . GetLevel ( module ) }

// IsEnabledFor will return true if logging is enabled for the given module.

IsEnabledFor will return true if logging is enabled for the given module .


func MultiLogger(backends ...Backend) LeveledBackend {
	var leveledBackends []LeveledBackend
	for _, backend := range backends {
		leveledBackends = append(leveledBackends, AddModuleLevel(backend))
	}
	return &multiLogger{leveledBackends}
}

func MultiLogger ( backends ... Backend ) LeveledBackend { var leveledBackends [ ] LeveledBackend for _ , backend := range backends { leveledBackends = append ( leveledBackends , AddModuleLevel ( backend ) ) } return & multiLogger { leveledBackends } }

// MultiLogger creates a logger which contain multiple loggers.

MultiLogger creates a logger which contain multiple loggers .


func (b *multiLogger) Log(level Level, calldepth int, rec *Record) (err error) {
	for _, backend := range b.backends {
		if backend.IsEnabledFor(level, rec.Module) {
			// Shallow copy of the record for the formatted cache on Record and get the
			// record formatter from the backend.
			r2 := *rec
			if e := backend.Log(level, calldepth+1, &r2); e != nil {
				err = e
			}
		}
	}
	return
}

// Log passes the log record to all backends.

Log passes the log record to all backends .


func (b *multiLogger) GetLevel(module string) Level {
	var level Level
	for _, backend := range b.backends {
		if backendLevel := backend.GetLevel(module); backendLevel > level {
			level = backendLevel
		}
	}
	return level
}

func ( b * multiLogger ) GetLevel ( module string ) Level { var level Level for _ , backend := range b . backends { if backendLevel := backend . GetLevel ( module ) ; backendLevel > level { level = backendLevel } } return level }

// GetLevel returns the highest level enabled by all backends.

GetLevel returns the highest level enabled by all backends .


func (b *multiLogger) SetLevel(level Level, module string) {
	for _, backend := range b.backends {
		backend.SetLevel(level, module)
	}
}

func ( b * multiLogger ) SetLevel ( level Level , module string ) { for _ , backend := range b . backends { backend . SetLevel ( level , module ) } }

// SetLevel propagates the same level to all backends.

SetLevel propagates the same level to all backends .


func (b *multiLogger) IsEnabledFor(level Level, module string) bool {
	for _, backend := range b.backends {
		if backend.IsEnabledFor(level, module) {
			return true
		}
	}
	return false
}

func ( b * multiLogger ) IsEnabledFor ( level Level , module string ) bool { for _ , backend := range b . backends { if backend . IsEnabledFor ( level , module ) { return true } } return false }

// IsEnabledFor returns true if any of the backends are enabled for it.

IsEnabledFor returns true if any of the backends are enabled for it .


func ConvertColors(colors []int, bold bool) []string {
	converted := []string{}
	for _, i := range colors {
		if bold {
			converted = append(converted, ColorSeqBold(color(i)))
		} else {
			converted = append(converted, ColorSeq(color(i)))
		}
	}

	return converted
}

func ConvertColors ( colors [ ] int , bold bool ) [ ] string { converted := [ ] string { } for _ , i := range colors { if bold { converted = append ( converted , ColorSeqBold ( color ( i ) ) ) } else { converted = append ( converted , ColorSeq ( color ( i ) ) ) } } return converted }

// ConvertColors takes a list of ints representing colors for log levels and
// converts them into strings for ANSI color formatting

ConvertColors takes a list of ints representing colors for log levels and converts them into strings for ANSI color formatting


func NewSyslogBackend(prefix string) (b *SyslogBackend, err error) {
	var w *syslog.Writer
	w, err = syslog.New(syslog.LOG_CRIT, prefix)
	return &SyslogBackend{w}, err
}

func NewSyslogBackend ( prefix string ) ( b * SyslogBackend , err error ) { var w * syslog . Writer w , err = syslog . New ( syslog . LOG_CRIT , prefix ) return & SyslogBackend { w } , err }

// NewSyslogBackend connects to the syslog daemon using UNIX sockets with the
// given prefix. If prefix is not given, the prefix will be derived from the
// launched command.

NewSyslogBackend connects to the syslog daemon using UNIX sockets with the given prefix . If prefix is not given the prefix will be derived from the launched command .


func NewSyslogBackendPriority(prefix string, priority syslog.Priority) (b *SyslogBackend, err error) {
	var w *syslog.Writer
	w, err = syslog.New(priority, prefix)
	return &SyslogBackend{w}, err
}

func NewSyslogBackendPriority ( prefix string , priority syslog . Priority ) ( b * SyslogBackend , err error ) { var w * syslog . Writer w , err = syslog . New ( priority , prefix ) return & SyslogBackend { w } , err }

// NewSyslogBackendPriority is the same as NewSyslogBackend, but with custom
// syslog priority, like syslog.LOG_LOCAL3|syslog.LOG_DEBUG etc.

NewSyslogBackendPriority is the same as NewSyslogBackend but with custom syslog priority like syslog . LOG_LOCAL3|syslog . LOG_DEBUG etc .


func SetBackend(backends ...Backend) LeveledBackend {
	var backend Backend
	if len(backends) == 1 {
		backend = backends[0]
	} else {
		backend = MultiLogger(backends...)
	}

	defaultBackend = AddModuleLevel(backend)
	return defaultBackend
}

func SetBackend ( backends ... Backend ) LeveledBackend { var backend Backend if len ( backends ) == 1 { backend = backends [ 0 ] } else { backend = MultiLogger ( backends ... ) } defaultBackend = AddModuleLevel ( backend ) return defaultBackend }

// SetBackend replaces the backend currently set with the given new logging
// backend.

SetBackend replaces the backend currently set with the given new logging backend .


func NewCommander(topLevelFlags *flag.FlagSet, name string) *Commander {
	cdr := &Commander{
		topFlags: topLevelFlags,
		name:     name,
		Output:   os.Stdout,
		Error:    os.Stderr,
	}
	topLevelFlags.Usage = func() { cdr.explain(cdr.Error) }
	return cdr
}

func NewCommander ( topLevelFlags * flag . FlagSet , name string ) * Commander { cdr := & Commander { topFlags : topLevelFlags , name : name , Output : os . Stdout , Error : os . Stderr , } topLevelFlags . Usage = func ( ) { cdr . explain ( cdr . Error ) } return cdr }

// NewCommander returns a new commander with the specified top-level
// flags and command name. The Usage function for the topLevelFlags
// will be set as well.

NewCommander returns a new commander with the specified top - level flags and command name . The Usage function for the topLevelFlags will be set as well .


func (cdr *Commander) Execute(ctx context.Context, args ...interface{}) ExitStatus {
	if cdr.topFlags.NArg() < 1 {
		cdr.topFlags.Usage()
		return ExitUsageError
	}

	name := cdr.topFlags.Arg(0)

	for _, group := range cdr.commands {
		for _, cmd := range group.commands {
			if name != cmd.Name() {
				continue
			}
			f := flag.NewFlagSet(name, flag.ContinueOnError)
			f.Usage = func() { explain(cdr.Error, cmd) }
			cmd.SetFlags(f)
			if f.Parse(cdr.topFlags.Args()[1:]) != nil {
				return ExitUsageError
			}
			return cmd.Execute(ctx, f, args...)
		}
	}

	// Cannot find this command.
	cdr.topFlags.Usage()
	return ExitUsageError
}

func
(
cdr
*
Commander
)
Execute
(
ctx
context
.
Context
,
args
...
interface
{
}
)
ExitStatus
{
if
cdr
.
topFlags
.
NArg
(
)
<
1
{
cdr
.
topFlags
.
Usage
(
)
return
ExitUsageError
}
name
:=
cdr
.
topFlags
.
Arg
(
0
)
for
_
,
group
:=
range
cdr
.
commands
{
for
_
,
cmd
:=
range
group
.
commands
{
if
name
!=
cmd
.
Name
(
)
{
continue
}
f
:=
flag
.
NewFlagSet
(
name
,
flag
.
ContinueOnError
)
f
.
Usage
=
func
(
)
{
explain
(
cdr
.
Error
,
cmd
)
}
cmd
.
SetFlags
(
f
)
if
f
.
Parse
(
cdr
.
topFlags
.
Args
(
)
[
1
:
]
)
!=
{
return
ExitUsageError
}
return
cmd
.
Execute
(
ctx
,
f
,
args
...
)
}
}
// Cannot find this command.
cdr
.
topFlags
.
Usage
(
)
return
ExitUsageError
}

// Execute should be called once the top-level-flags on a Commander
// have been initialized. It finds the correct subcommand and executes
// it, and returns an ExitStatus with the result. On a usage error, an
// appropriate message is printed to os.Stderr, and ExitUsageError is
// returned. The additional args are provided as-is to the Execute method
// of the selected Command.

Execute should be called once the top - level - flags on a Commander have been initialized . It finds the correct subcommand and executes it and returns an ExitStatus with the result . On a usage error an appropriate message is printed to os . Stderr and ExitUsageError is returned . The additional args are provided as - is to the Execute method of the selected Command .


func (cdr *Commander) explain(w io.Writer) {
	fmt.Fprintf(w, "Usage: %s <flags> <subcommand> <subcommand args>\n\n", cdr.name)
	sort.Sort(byGroupName(cdr.commands))
	for _, group := range cdr.commands {
		explainGroup(w, group)
	}
	if cdr.topFlags == nil {
		fmt.Fprintln(w, "\nNo top level flags.")
		return
	}
	if len(cdr.important) == 0 {
		fmt.Fprintf(w, "\nUse \"%s flags\" for a list of top-level flags\n", cdr.name)
		return
	}

	fmt.Fprintf(w, "\nTop-level flags (use \"%s flags\" for a full list):\n", cdr.name)
	for _, name := range cdr.important {
		f := cdr.topFlags.Lookup(name)
		if f == nil {
			panic(fmt.Sprintf("Important flag (%s) is not defined", name))
		}
		fmt.Fprintf(w, "  -%s=%s: %s\n", f.Name, f.DefValue, f.Usage)
	}
}

func ( cdr * Commander ) explain ( w io . Writer ) { fmt . Fprintf ( w , " \n \n " , cdr . name ) sort . Sort ( byGroupName ( cdr . commands ) ) for _ , group := range cdr . commands { explainGroup ( w , group ) } if cdr . topFlags == nil { fmt . Fprintln ( w , " \n " ) return } if len ( cdr . important ) == 0 { fmt . Fprintf ( w , " \n \" \" \n " , cdr . name ) return } fmt . Fprintf ( w , " \n \" \" \n " , cdr . name ) for _ , name := range cdr . important { f := cdr . topFlags . Lookup ( name ) if f == nil { panic ( fmt . Sprintf ( " " , name ) ) } fmt . Fprintf ( w , " \n " , f . Name , f . DefValue , f . Usage ) } }

// explain prints a brief description of all the subcommands and the
// important top-level flags.

explain prints a brief description of all the subcommands and the important top - level flags .


func explainGroup(w io.Writer, group *commandGroup) {
	if len(group.commands) == 0 {
		return
	}
	if group.name == "" {
		fmt.Fprintf(w, "Subcommands:\n")
	} else {
		fmt.Fprintf(w, "Subcommands for %s:\n", group.name)
	}
	sort.Sort(group)

	aliases := make(map[string][]string)
	for _, cmd := range group.commands {
		if alias, ok := cmd.(*aliaser); ok {
			root := dealias(alias).Name()

			if _, ok := aliases[root]; !ok {
				aliases[root] = []string{}
			}
			aliases[root] = append(aliases[root], alias.Name())
		}
	}

	for _, cmd := range group.commands {
		if _, ok := cmd.(*aliaser); ok {
			continue
		}

		name := cmd.Name()
		names := []string{name}

		if a, ok := aliases[name]; ok {
			names = append(names, a...)
		}

		fmt.Fprintf(w, "\t%-15s  %s\n", strings.Join(names, ", "), cmd.Synopsis())
	}
	fmt.Fprintln(w)
}

func explainGroup ( w io . Writer , group * commandGroup ) { if len ( group . commands ) == 0 { return } if group . name == " " { fmt . Fprintf ( w , " \n " ) } else { fmt . Fprintf ( w , " \n " , group . name ) } sort . Sort ( group ) aliases := make ( map [ string ] [ ] string ) for _ , cmd := range group . commands { if alias , ok := cmd . ( * aliaser ) ; ok { root := dealias ( alias ) . Name ( ) if _ , ok := aliases [ root ] ; ! ok { aliases [ root ] = [ ] string { } } aliases [ root ] = append ( aliases [ root ] , alias . Name ( ) ) } } for _ , cmd := range group . commands { if _ , ok := cmd . ( * aliaser ) ; ok { continue } name := cmd . Name ( ) names := [ ] string { name } if a , ok := aliases [ name ] ; ok { names = append ( names , a ... ) } fmt . Fprintf ( w , " \t \n " , strings . Join ( names , " " ) , cmd . Synopsis ( ) ) } fmt . Fprintln ( w ) }

// explainGroup explains all the subcommands for a particular group.

explainGroup explains all the subcommands for a particular group .


func explain(w io.Writer, cmd Command) {
	fmt.Fprintf(w, "%s", cmd.Usage())
	subflags := flag.NewFlagSet(cmd.Name(), flag.PanicOnError)
	subflags.SetOutput(w)
	cmd.SetFlags(subflags)
	subflags.PrintDefaults()
}

func explain ( w io . Writer , cmd Command ) { fmt . Fprintf ( w , " " , cmd . Usage ( ) ) subflags := flag . NewFlagSet ( cmd . Name ( ) , flag . PanicOnError ) subflags . SetOutput ( w ) cmd . SetFlags ( subflags ) subflags . PrintDefaults ( ) }

// explainCmd prints a brief description of a single command.

explainCmd prints a brief description of a single command .


func dealias(cmd Command) Command {
	if alias, ok := cmd.(*aliaser); ok {
		return dealias(alias.Command)
	}

	return cmd
}

func dealias ( cmd Command ) Command { if alias , ok := cmd . ( * aliaser ) ; ok { return dealias ( alias . Command ) } return cmd }

// dealias recursivly dealiases a command until a non-aliased command
// is reached.

dealias recursivly dealiases a command until a non - aliased command is reached .


func Execute(ctx context.Context, args ...interface{}) ExitStatus {
	return DefaultCommander.Execute(ctx, args...)
}

func Execute ( ctx context . Context , args ... interface { } ) ExitStatus { return DefaultCommander . Execute ( ctx , args ... ) }

// Execute should be called once the default flags have been
// initialized by flag.Parse. It finds the correct subcommand and
// executes it, and returns an ExitStatus with the result. On a usage
// error, an appropriate message is printed to os.Stderr, and
// ExitUsageError is returned. The additional args are provided as-is
// to the Execute method of the selected Command. It is a wrapper
// around DefaultCommander.Execute.

Execute should be called once the default flags have been initialized by flag . Parse . It finds the correct subcommand and executes it and returns an ExitStatus with the result . On a usage error an appropriate message is printed to os . Stderr and ExitUsageError is returned . The additional args are provided as - is to the Execute method of the selected Command . It is a wrapper around DefaultCommander . Execute .


func LoadFromData(data []byte) (c *ConfigFile, err error) {
	// Save memory data to temporary file to support further operations.
	tmpName := path.Join(os.TempDir(), "goconfig", fmt.Sprintf("%d", time.Now().Nanosecond()))
	if err = os.MkdirAll(path.Dir(tmpName), os.ModePerm); err != nil {
		return nil, err
	}
	if err = ioutil.WriteFile(tmpName, data, 0655); err != nil {
		return nil, err
	}

	c = newConfigFile([]string{tmpName})
	err = c.read(bytes.NewBuffer(data))
	return c, err
}

// LoadFromData accepts raw data directly from memory
// and returns a new configuration representation.
// Note that the configuration is written to the system
// temporary folder, so your file should not contain
// sensitive information.

LoadFromData accepts raw data directly from memory and returns a new configuration representation . Note that the configuration is written to the system temporary folder so your file should not contain sensitive information .