// Sends a "create cluster" request to the API client based on the cli.Context // Returns an error if one occurred func createCluster(c *cli.Context, w io.Writer) error { err := checkArgCount(c, 0) if err != nil { return err } tenantName := c.String("tenant") projectName := c.String("project") name := c.String("name") cluster_type := c.String("type") vm_flavor := c.String("vm_flavor") disk_flavor := c.String("disk_flavor") network_id := c.String("network_id") worker_count := c.Int("worker_count") dns := c.String("dns") gateway := c.String("gateway") netmask := c.String("netmask") master_ip := c.String("master-ip") container_network := c.String("container-network") etcd1 := c.String("etcd1") etcd2 := c.String("etcd2") etcd3 := c.String("etcd3") batch_size := c.Int("batchSize") ssh_key := c.String("ssh-key") ca_cert := c.String("registry-ca-cert") admin_password := c.String("admin-password") if admin_password != "" { result := validateHarborPassword(admin_password) if result != true { return fmt.Errorf("The Harbor password is invalid. It should have at least 7 characters " + "with 1 lowercase letter, 1 capital letter and 1 numeric character.") } } wait_for_ready := c.IsSet("wait-for-ready") const DEFAULT_WORKER_COUNT = 1 client.Esxclient, err = client.GetClient(c) if err != nil { return err } tenant, err := verifyTenant(tenantName) if err != nil { return err } project, err := verifyProject(tenant.ID, projectName) if err != nil { return err } if !c.GlobalIsSet("non-interactive") { name, err = askForInput("Cluster name: ", name) if err != nil { return err } cluster_type, err = askForInput("Cluster type: ", cluster_type) if err != nil { return err } if worker_count == 0 && cluster_type != "HARBOR" { worker_count_string, err := askForInput("Worker count: ", "") if err != nil { return err } worker_count, err = strconv.Atoi(worker_count_string) if err != nil { return fmt.Errorf("Please supply a valid worker count") } } } if len(name) == 0 || len(cluster_type) == 0 { return fmt.Errorf("Provide a valid cluster name and type") } if worker_count == 0 && cluster_type != "HARBOR" { worker_count = DEFAULT_WORKER_COUNT } if !c.GlobalIsSet("non-interactive") { dns, err = askForInput("Cluster DNS server: ", dns) if err != nil { return err } gateway, err = askForInput("Cluster network gateway: ", gateway) if err != nil { return err } netmask, err = askForInput("Cluster network netmask: ", netmask) if err != nil { return err } ssh_key, err = askForInput("Cluster ssh key file path (leave blank for none): ", ssh_key) if err != nil { return err } } if len(dns) == 0 || len(gateway) == 0 || len(netmask) == 0 { return fmt.Errorf("Provide a valid DNS, gateway, and netmask") } extended_properties := make(map[string]string) extended_properties[photon.ExtendedPropertyDNS] = dns extended_properties[photon.ExtendedPropertyGateway] = gateway extended_properties[photon.ExtendedPropertyNetMask] = netmask if len(ssh_key) != 0 { ssh_key_content, err := readSSHKey(ssh_key) if err == nil { extended_properties[photon.ExtendedPropertySSHKey] = ssh_key_content } else { return err } } if len(ca_cert) != 0 { ca_cert_content, err := readCACert(ca_cert) if err == nil { extended_properties[photon.ExtendedPropertyRegistryCACert] = ca_cert_content } else { return err } } cluster_type = strings.ToUpper(cluster_type) switch cluster_type { case "KUBERNETES": if !c.GlobalIsSet("non-interactive") { master_ip, err = askForInput("Kubernetes master static IP address: ", master_ip) if err != nil { return err } container_network, err = askForInput("Kubernetes worker network ID: ", container_network) if err != nil { return err } etcd1, err = askForInput("etcd server 1 static IP address: ", etcd1) if err != nil { return err } etcd2, err = askForInput("etcd server 2 static IP address (leave blank for none): ", etcd2) if err != nil { return err } if len(etcd2) != 0 { etcd3, err = askForInput("etcd server 3 static IP address (leave blank for none): ", etcd3) if err != nil { return err } } } extended_properties[photon.ExtendedPropertyMasterIP] = master_ip extended_properties[photon.ExtendedPropertyContainerNetwork] = container_network extended_properties[photon.ExtendedPropertyETCDIP1] = etcd1 if len(etcd2) != 0 { extended_properties[photon.ExtendedPropertyETCDIP2] = etcd2 if len(etcd3) != 0 { extended_properties[photon.ExtendedPropertyETCDIP3] = etcd3 } } case "HARBOR": if !c.GlobalIsSet("non-interactive") { master_ip, err = askForInput("Harbor master static IP address: ", master_ip) if err != nil { return err } if len(admin_password) == 0 { fmt.Printf("Harbor registry admin password: "******"The Harbor password is invalid. It should have at least 7 " + "characters with 1 lowercase letter, 1 capital letter and 1 numeric " + "character.") } fmt.Printf("\n") } } extended_properties[photon.ExtendedPropertyMasterIP] = master_ip extended_properties[photon.ExtendedPropertyAdminPassword] = admin_password default: return fmt.Errorf("Unsupported cluster type: %s", cluster_type) } clusterSpec := photon.ClusterCreateSpec{} clusterSpec.Name = name clusterSpec.Type = cluster_type clusterSpec.VMFlavor = vm_flavor clusterSpec.DiskFlavor = disk_flavor clusterSpec.NetworkID = network_id clusterSpec.WorkerCount = worker_count clusterSpec.BatchSizeWorker = batch_size clusterSpec.ExtendedProperties = extended_properties if !c.GlobalIsSet("non-interactive") { fmt.Printf("\n") fmt.Printf("Creating cluster: %s (%s)\n", clusterSpec.Name, clusterSpec.Type) if len(clusterSpec.VMFlavor) != 0 { fmt.Printf(" VM flavor: %s\n", clusterSpec.VMFlavor) } if len(clusterSpec.DiskFlavor) != 0 { fmt.Printf(" Disk flavor: %s\n", clusterSpec.DiskFlavor) } if clusterSpec.Type != "HARBOR" { fmt.Printf(" Worker count: %d\n", clusterSpec.WorkerCount) } if clusterSpec.BatchSizeWorker != 0 { fmt.Printf(" Batch size: %d\n", clusterSpec.BatchSizeWorker) } fmt.Printf("\n") } if confirmed(c) { createTask, err := client.Esxclient.Projects.CreateCluster(project.ID, &clusterSpec) if err != nil { return err } _, err = waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if wait_for_ready { if !utils.NeedsFormatting(c) { fmt.Printf("Waiting for cluster %s to become ready\n", createTask.Entity.ID) } cluster, err := waitForCluster(createTask.Entity.ID) if err != nil { return err } if utils.NeedsFormatting(c) { utils.FormatObject(cluster, w, c) } else { fmt.Printf("Cluster %s is ready\n", cluster.ID) } } else { fmt.Println("Note: the cluster has been created with minimal resources. You can use the cluster now.") fmt.Println("A background task is running to gradually expand the cluster to its target capacity.") fmt.Printf("You can run 'cluster show %s' to see the state of the cluster.\n", createTask.Entity.ID) } } else { fmt.Println("Cancelled") } return nil }
// Sends a "create cluster" request to the API client based on the cli.Context // Returns an error if one occurred func createCluster(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "cluster create [<options>]") if err != nil { return err } tenantName := c.String("tenant") projectName := c.String("project") name := c.String("name") cluster_type := c.String("type") vm_flavor := c.String("vm_flavor") disk_flavor := c.String("disk_flavor") network_id := c.String("network_id") worker_count := c.Int("worker_count") dns := c.String("dns") gateway := c.String("gateway") netmask := c.String("netmask") master_ip := c.String("master-ip") container_network := c.String("container-network") zookeeper1 := c.String("zookeeper1") zookeeper2 := c.String("zookeeper2") zookeeper3 := c.String("zookeeper3") etcd1 := c.String("etcd1") etcd2 := c.String("etcd2") etcd3 := c.String("etcd3") batch_size := c.Int("batchSize") ssh_key := c.String("ssh-key") wait_for_ready := c.IsSet("wait-for-ready") const DEFAULT_WORKER_COUNT = 1 client.Esxclient, err = client.GetClient(c.GlobalIsSet("non-interactive")) if err != nil { return err } tenant, err := verifyTenant(tenantName) if err != nil { return err } project, err := verifyProject(tenant.ID, projectName) if err != nil { return err } if !utils.IsNonInteractive(c) { name, err = askForInput("Cluster name: ", name) if err != nil { return err } cluster_type, err = askForInput("Cluster type: ", cluster_type) if err != nil { return err } if worker_count == 0 { worker_count_string, err := askForInput("Worker count: ", "") if err != nil { return err } worker_count, err = strconv.Atoi(worker_count_string) if err != nil { return fmt.Errorf("Please supply a valid worker count") } } } if len(name) == 0 || len(cluster_type) == 0 { return fmt.Errorf("Provide a valid cluster name and type") } if worker_count == 0 { worker_count = DEFAULT_WORKER_COUNT } if !utils.IsNonInteractive(c) { dns, err = askForInput("Cluster DNS server: ", dns) if err != nil { return err } gateway, err = askForInput("Cluster network gateway: ", gateway) if err != nil { return err } netmask, err = askForInput("Cluster network netmask: ", netmask) if err != nil { return err } ssh_key, err = askForInput("Cluster ssh key file path (leave blank for none): ", ssh_key) if err != nil { return err } } if len(dns) == 0 || len(gateway) == 0 || len(netmask) == 0 { return fmt.Errorf("Provide a valid DNS, gateway, and netmask") } extended_properties := make(map[string]string) extended_properties[photon.ExtendedPropertyDNS] = dns extended_properties[photon.ExtendedPropertyGateway] = gateway extended_properties[photon.ExtendedPropertyNetMask] = netmask if len(ssh_key) != 0 { ssh_key_content, err := readSSHKey(ssh_key) if err == nil { extended_properties[photon.ExtendedPropertySSHKey] = ssh_key_content } else { return err } } cluster_type = strings.ToUpper(cluster_type) switch cluster_type { case "KUBERNETES": if !utils.IsNonInteractive(c) { master_ip, err = askForInput("Kubernetes master static IP address: ", master_ip) if err != nil { return err } container_network, err = askForInput("Kubernetes worker network ID: ", container_network) if err != nil { return err } etcd1, err = askForInput("etcd server 1 static IP address: ", etcd1) if err != nil { return err } etcd2, err = askForInput("etcd server 2 static IP address (leave blank for none): ", etcd2) if err != nil { return err } if len(etcd2) != 0 { etcd3, err = askForInput("etcd server 3 static IP address (leave blank for none): ", etcd3) if err != nil { return err } } } extended_properties[photon.ExtendedPropertyMasterIP] = master_ip extended_properties[photon.ExtendedPropertyContainerNetwork] = container_network extended_properties[photon.ExtendedPropertyETCDIP1] = etcd1 if len(etcd2) != 0 { extended_properties[photon.ExtendedPropertyETCDIP2] = etcd2 if len(etcd3) != 0 { extended_properties[photon.ExtendedPropertyETCDIP3] = etcd3 } } case "MESOS": if !utils.IsNonInteractive(c) { zookeeper1, err = askForInput("Zookeeper server 1 static IP address: ", zookeeper1) if err != nil { return err } zookeeper2, err = askForInput("Zookeeper server 2 static IP address (leave blank for none): ", zookeeper2) if err != nil { return err } if len(zookeeper2) != 0 { zookeeper3, err = askForInput("Zookeeper server 3 static IP address (leave blank for none): ", zookeeper3) if err != nil { return err } } } extended_properties[photon.ExtendedPropertyZookeeperIP1] = zookeeper1 if len(zookeeper2) != 0 { extended_properties[photon.ExtendedPropertyZookeeperIP2] = zookeeper2 if len(zookeeper3) != 0 { extended_properties[photon.ExtendedPropertyZookeeperIP3] = zookeeper3 } } case "SWARM": if !utils.IsNonInteractive(c) { etcd1, err = askForInput("etcd server 1 static IP address: ", etcd1) if err != nil { return err } etcd2, err = askForInput("etcd server 2 static IP address (leave blank for none): ", etcd2) if err != nil { return err } if len(etcd2) != 0 { etcd3, err = askForInput("etcd server 3 static IP address (leave blank for none): ", etcd3) if err != nil { return err } } } extended_properties[photon.ExtendedPropertyETCDIP1] = etcd1 if len(etcd2) != 0 { extended_properties[photon.ExtendedPropertyETCDIP2] = etcd2 if len(etcd3) != 0 { extended_properties[photon.ExtendedPropertyETCDIP3] = etcd3 } } default: return fmt.Errorf("Unsupported cluster type: %s", cluster_type) } clusterSpec := photon.ClusterCreateSpec{} clusterSpec.Name = name clusterSpec.Type = cluster_type clusterSpec.VMFlavor = vm_flavor clusterSpec.DiskFlavor = disk_flavor clusterSpec.NetworkID = network_id clusterSpec.WorkerCount = worker_count clusterSpec.BatchSizeWorker = batch_size clusterSpec.ExtendedProperties = extended_properties if !utils.IsNonInteractive(c) { fmt.Printf("\n") fmt.Printf("Creating cluster: %s (%s)\n", clusterSpec.Name, clusterSpec.Type) if len(clusterSpec.VMFlavor) != 0 { fmt.Printf(" VM flavor: %s\n", clusterSpec.VMFlavor) } if len(clusterSpec.DiskFlavor) != 0 { fmt.Printf(" Disk flavor: %s\n", clusterSpec.DiskFlavor) } fmt.Printf(" Worker count: %d\n", clusterSpec.WorkerCount) if clusterSpec.BatchSizeWorker != 0 { fmt.Printf(" Batch size: %d\n", clusterSpec.BatchSizeWorker) } fmt.Printf("\n") } if confirmed(utils.IsNonInteractive(c)) { createTask, err := client.Esxclient.Projects.CreateCluster(project.ID, &clusterSpec) if err != nil { return err } _, err = waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if wait_for_ready { if !utils.NeedsFormatting(c) { fmt.Printf("Waiting for cluster %s to become ready\n", createTask.Entity.ID) } cluster, err := waitForCluster(createTask.Entity.ID) if err != nil { return err } if utils.NeedsFormatting(c) { utils.FormatObject(cluster, w, c) } else { fmt.Printf("Cluster %s is ready\n", cluster.ID) } } else { fmt.Println("Note: the cluster has been created with minimal resources. You can use the cluster now.") fmt.Println("A background task is running to gradually expand the cluster to its target capacity.") fmt.Printf("You can run 'cluster show %s' to see the state of the cluster.\n", createTask.Entity.ID) } } else { fmt.Println("Cancelled") } return nil }