Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
kubicorn/cmd/create.go
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
253 lines (224 sloc)
8.26 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © 2017 The Kubicorn Authors | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
package cmd | |
import ( | |
"fmt" | |
"os" | |
"strings" | |
"encoding/json" | |
"github.com/kubicorn/kubicorn/apis/cluster" | |
"github.com/kubicorn/kubicorn/pkg/cli" | |
"github.com/kubicorn/kubicorn/pkg/kubeconfig" | |
"github.com/kubicorn/kubicorn/pkg/logger" | |
"github.com/kubicorn/kubicorn/pkg/namer" | |
"github.com/spf13/cobra" | |
"github.com/spf13/viper" | |
"k8s.io/kube-deploy/cluster-api/api/cluster/v1alpha1" | |
) | |
// CreateCmd represents create command | |
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 | |
} | |
// RunCreate is the starting point when a user runs the create command. | |
func RunCreate(options *cli.CreateOptions) error { | |
// Create our cluster resource | |
name := options.Name | |
var newCluster *cluster.Cluster | |
if _, ok := cli.ProfileMapIndexed[options.Profile]; ok { | |
newCluster = cli.ProfileMapIndexed[options.Profile].ProfileFunc(name) | |
} else { | |
return fmt.Errorf("Invalid profile [%s]", options.Profile) | |
} | |
if options.KubeConfigLocalFile != "" { | |
if newCluster.Annotations == nil { | |
newCluster.Annotations = make(map[string]string) | |
} | |
newCluster.Annotations[kubeconfig.ClusterAnnotationKubeconfigLocalFile] = options.KubeConfigLocalFile | |
} | |
if len(options.Set) > 0 { | |
// Here we override Set options | |
for _, set := range options.Set { | |
parts := strings.SplitN(set, "=", 2) | |
if len(parts) == 1 { | |
continue | |
} | |
providerConfig := newCluster.ProviderConfig() | |
err := cli.SwalkerWrite(strings.Title(parts[0]), providerConfig, parts[1]) | |
if err != nil { | |
//fmt.Println(1) | |
return fmt.Errorf("Invalid --set: %v", err) | |
} | |
newCluster.SetProviderConfig(providerConfig) | |
} | |
} | |
if len(options.MasterSet) > 0 { | |
// Here we override MasterSet options | |
for _, set := range options.MasterSet { | |
parts := strings.SplitN(set, "=", 2) | |
if len(parts) == 1 { | |
continue | |
} | |
for i, ms := range newCluster.MachineSets { | |
isMaster := false | |
for _, role := range ms.Spec.Template.Spec.Roles { | |
if role == v1alpha1.MasterRole { | |
isMaster = true | |
break | |
} | |
} | |
if !isMaster { | |
continue | |
} | |
pcStr := ms.Spec.Template.Spec.ProviderConfig | |
providerConfig := &cluster.MachineProviderConfig{} | |
json.Unmarshal([]byte(pcStr), providerConfig) | |
err := cli.SwalkerWrite(strings.Title(parts[0]), providerConfig, parts[1]) | |
if err != nil { | |
//fmt.Println(2) | |
return fmt.Errorf("Invalid --set: %v", err) | |
} | |
// Now set the provider config | |
bytes, err := json.Marshal(providerConfig) | |
if err != nil { | |
logger.Critical("Unable to marshal provider config: %v", err) | |
return err | |
} | |
str := string(bytes) | |
newCluster.MachineSets[i].Spec.Template.Spec.ProviderConfig = str | |
} | |
} | |
} | |
if len(options.NodeSet) > 0 { | |
// Here we override NodeSet options | |
for _, set := range options.NodeSet { | |
parts := strings.SplitN(set, "=", 2) | |
if len(parts) == 1 { | |
continue | |
} | |
for i, ms := range newCluster.MachineSets { | |
isNode := false | |
for _, role := range ms.Spec.Template.Spec.Roles { | |
if role == v1alpha1.NodeRole { | |
isNode = true | |
break | |
} | |
} | |
if !isNode { | |
continue | |
} | |
pcStr := ms.Spec.Template.Spec.ProviderConfig | |
providerConfig := &cluster.MachineProviderConfig{} | |
json.Unmarshal([]byte(pcStr), providerConfig) | |
err := cli.SwalkerWrite(strings.Title(parts[0]), providerConfig, parts[1]) | |
if err != nil { | |
//fmt.Println(3) | |
return fmt.Errorf("Invalid --set: %v", err) | |
} | |
// Now set the provider config | |
bytes, err := json.Marshal(providerConfig) | |
if err != nil { | |
logger.Critical("Unable to marshal provider config: %v", err) | |
return err | |
} | |
str := string(bytes) | |
newCluster.MachineSets[i].Spec.Template.Spec.ProviderConfig = str | |
} | |
} | |
} | |
if len(options.AwsOptions.PolicyAttachments) > 0 { | |
for i, ms := range newCluster.MachineSets { | |
pcStr := ms.Spec.Template.Spec.ProviderConfig | |
providerConfig := &cluster.MachineProviderConfig{} | |
if err := json.Unmarshal([]byte(pcStr), providerConfig); err != nil { | |
logger.Critical("Unable to unmarshal provider config: %v", err) | |
return err | |
} | |
if providerConfig.ServerPool != nil && providerConfig.ServerPool.InstanceProfile != nil && providerConfig.ServerPool.InstanceProfile.Role != nil { | |
providerConfig.ServerPool.InstanceProfile.Role.PolicyAttachments = options.AwsOptions.PolicyAttachments | |
} | |
// Now set the provider config | |
bytes, err := json.Marshal(providerConfig) | |
if err != nil { | |
logger.Critical("Unable to marshal provider config: %v", err) | |
return err | |
} | |
str := string(bytes) | |
newCluster.MachineSets[i].Spec.Template.Spec.ProviderConfig = str | |
} | |
} | |
if newCluster.ProviderConfig().Cloud == cluster.CloudGoogle && options.CloudID == "" { | |
return fmt.Errorf("CloudID is required for google cloud. Please set it to your project ID") | |
} | |
providerConfig := newCluster.ProviderConfig() | |
providerConfig.CloudId = options.CloudID | |
newCluster.SetProviderConfig(providerConfig) | |
// Expand state store path | |
// Todo (@kris-nova) please pull this into a filepath package or something | |
options.StateStorePath = cli.ExpandPath(options.StateStorePath) | |
// Register state store and check if it exists | |
stateStore, err := options.NewStateStore() | |
if err != nil { | |
return err | |
} else if stateStore.Exists() { | |
return fmt.Errorf("State store [%s] exists, will not overwrite. Delete existing profile [%s] and retry", name, options.StateStorePath+"/"+name) | |
} | |
// Init new state store with the cluster resource | |
err = stateStore.Commit(newCluster) | |
if err != nil { | |
return fmt.Errorf("Unable to init state store: %v", err) | |
} | |
logger.Always("The state [%s/%s/cluster.yaml] has been created. You can edit the file, then run `kubicorn apply %s`", options.StateStorePath, name, name) | |
return nil | |
} |