// Retrieves availability zone against specified id. func showAvailabilityZone(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "availability-zone show <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } zone, err := client.Esxclient.AvailabilityZones.Get(id) if err != nil { return err } if c.GlobalIsSet("non-interactive") { fmt.Printf("%s\t%s\t%s\t%s\n", zone.ID, zone.Name, zone.Kind, zone.State) } else if utils.NeedsFormatting(c) { utils.FormatObject(zone, w, c) } else { fmt.Printf("AvailabilityZone ID: %s\n", zone.ID) fmt.Printf(" Name: %s\n", zone.Name) fmt.Printf(" Kind: %s\n", zone.Kind) fmt.Printf(" State: %s\n", zone.State) } return nil }
func showNetwork(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "network show <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } network, err := client.Esxclient.Subnets.Get(id) if err != nil { return err } if c.GlobalIsSet("non-interactive") { portGroups := getCommaSeparatedStringFromStringArray(network.PortGroups) fmt.Printf("%s\t%s\t%s\t%s\t%s\t%t\n", network.ID, network.Name, network.State, portGroups, network.Description, network.IsDefault) } else if utils.NeedsFormatting(c) { utils.FormatObject(network, w, c) } else { fmt.Printf("Network ID: %s\n", network.ID) fmt.Printf(" Name: %s\n", network.Name) fmt.Printf(" State: %s\n", network.State) fmt.Printf(" Description: %s\n", network.Description) fmt.Printf(" Port Groups: %s\n", network.PortGroups) fmt.Printf(" Is Default: %t\n", network.IsDefault) } return nil }
// Set host's availability zone with the specified host ID, returns an error if one occurred func setHostAvailabilityZone(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 2, "host set-availability-zone <id> <availability-zone-id>") if err != nil { return err } id := c.Args().First() availabilityZoneId := c.Args()[1] client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } setAvailabilityZoneSpec := photon.HostSetAvailabilityZoneOperation{} setAvailabilityZoneSpec.AvailabilityZoneId = availabilityZoneId setTask, err := client.Esxclient.Hosts.SetAvailabilityZone(id, &setAvailabilityZoneSpec) if err != nil { return err } id, err = waitOnTaskOperation(setTask.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { host, err := client.Esxclient.Hosts.Get(id) if err != nil { return err } utils.FormatObject(host, w, c) } return nil }
func setDefaultNetwork(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "network set-default <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } task, err := client.Esxclient.Subnets.SetDefault(id) if err != nil { return err } if confirmed(utils.IsNonInteractive(c)) { id, err := waitOnTaskOperation(task.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { network, err := client.Esxclient.Subnets.Get(id) if err != nil { return err } utils.FormatObject(network, w, c) } } else { fmt.Println("OK. Canceled") } return nil }
// Sends a "resize cluster" request to the API client based on the cli.Context // Returns an error if one occurred func resizeCluster(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 2, "cluster resize <id> <new worker count> [<options>]") if err != nil { return err } cluster_id := c.Args()[0] worker_count_string := c.Args()[1] worker_count, err := strconv.Atoi(worker_count_string) wait_for_ready := c.IsSet("wait-for-ready") if len(cluster_id) == 0 || err != nil || worker_count <= 0 { return fmt.Errorf("Provide a valid cluster ID and worker count") } client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } if !utils.IsNonInteractive(c) { fmt.Printf("\nResizing cluster %s to worker count %d\n", cluster_id, worker_count) } if confirmed(utils.IsNonInteractive(c)) { resizeSpec := photon.ClusterResizeOperation{} resizeSpec.NewWorkerCount = worker_count resizeTask, err := client.Esxclient.Clusters.Resize(cluster_id, &resizeSpec) if err != nil { return err } _, err = waitOnTaskOperation(resizeTask.ID, c) if err != nil { return err } if wait_for_ready { cluster, err := waitForCluster(cluster_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: A background task is running to gradually resize the cluster to its target capacity.") fmt.Printf("You may continue to use the cluster. You can run 'cluster show %s'\n", resizeTask.Entity.ID) fmt.Println("to see the state of the cluster. If the resize operation is still in progress, the cluster state") fmt.Println("will show as RESIZING. Once the cluster is resized, the cluster state will show as READY.") } } else { fmt.Println("Cancelled") } return nil }
// Show project info with the specified project id, returns an error if one occurred func showProject(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "project show <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } project, err := client.Esxclient.Projects.Get(id) if err != nil { return err } if c.GlobalIsSet("non-interactive") { securityGroups := []string{} for _, s := range project.SecurityGroups { securityGroups = append(securityGroups, fmt.Sprintf("%s:%t", s.Name, s.Inherited)) } scriptSecurityGroups := strings.Join(securityGroups, ",") limits := quotaLineItemListToString(project.ResourceTicket.Limits) usages := quotaLineItemListToString(project.ResourceTicket.Usage) fmt.Printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n", project.ID, project.Name, project.ResourceTicket.TenantTicketID, project.ResourceTicket.TenantTicketName, limits, usages, scriptSecurityGroups) } else if utils.NeedsFormatting(c) { utils.FormatObject(project, w, c) } else { w := new(tabwriter.Writer) w.Init(os.Stdout, 4, 4, 2, ' ', 0) fmt.Fprintf(w, "Project ID: %s\n", project.ID) fmt.Fprintf(w, " Name: %s\n", project.Name) fmt.Fprintf(w, " TenantTicketID: %s\n", project.ResourceTicket.TenantTicketID) fmt.Fprintf(w, " TenantTicketName: %s\n", project.ResourceTicket.TenantTicketName) fmt.Fprintf(w, " Limits:\n") for _, l := range project.ResourceTicket.Limits { fmt.Fprintf(w, " %s\t%g\t%s\n", l.Key, l.Value, l.Unit) } fmt.Fprintf(w, " Usage:\n") for _, u := range project.ResourceTicket.Usage { fmt.Fprintf(w, " %s\t%g\t%s\n", u.Key, u.Value, u.Unit) } if len(project.SecurityGroups) != 0 { fmt.Fprintf(w, " SecurityGroups:\n") for _, s := range project.SecurityGroups { fmt.Fprintf(w, " %s\t%t\n", s.Name, s.Inherited) } } err = w.Flush() if err != nil { return err } } return nil }
// Sends a "show cluster" request to the API client based on the cli.Context // Returns an error if one occurred func showCluster(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "cluster show <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } cluster, err := client.Esxclient.Clusters.Get(id) if err != nil { return err } vms, err := client.Esxclient.Clusters.GetVMs(id) if err != nil { return err } var master_vms []photon.VM for _, vm := range vms.Items { for _, tag := range vm.Tags { if strings.Count(tag, ":") == 2 && !strings.Contains(strings.ToLower(tag), "worker") { master_vms = append(master_vms, vm) break } } } if c.GlobalIsSet("non-interactive") { extendedProperties := strings.Trim(strings.TrimLeft(fmt.Sprint(cluster.ExtendedProperties), "map"), "[]") fmt.Printf("%s\t%s\t%s\t%s\t%d\t%s\n", cluster.ID, cluster.Name, cluster.State, cluster.Type, cluster.WorkerCount, extendedProperties) } else if utils.NeedsFormatting(c) { utils.FormatObject(cluster, w, c) } else { fmt.Println("Cluster ID: ", cluster.ID) fmt.Println(" Name: ", cluster.Name) fmt.Println(" State: ", cluster.State) fmt.Println(" Type: ", cluster.Type) fmt.Println(" Worker count: ", cluster.WorkerCount) fmt.Println(" Extended Properties: ", cluster.ExtendedProperties) fmt.Println() } err = printClusterVMs(master_vms, c.GlobalIsSet("non-interactive")) if err != nil { return err } return nil }
// Shows an image based on id func showImage(c *cli.Context, w io.Writer) error { id := c.Args().First() if !utils.IsNonInteractive(c) { var err error id, err = askForInput("Image id: ", id) if err != nil { return err } } if len(id) == 0 { return fmt.Errorf("Please provide image id") } var err error client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } image, err := client.Esxclient.Images.Get(id) if err != nil { return err } if c.GlobalIsSet("non-interactive") { settings := []string{} for _, setting := range image.Settings { settings = append(settings, fmt.Sprintf("%s:%s", setting.Name, setting.DefaultValue)) } scriptSettings := strings.Join(settings, ",") fmt.Printf("%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", image.ID, image.Name, image.State, image.Size, image.ReplicationType, image.ReplicationProgress, image.SeedingProgress, scriptSettings) } else if utils.NeedsFormatting(c) { utils.FormatObject(image, w, c) } else { fmt.Printf("Image ID: %s\n", image.ID) fmt.Printf(" Name: %s\n", image.Name) fmt.Printf(" State: %s\n", image.State) fmt.Printf(" Size: %d Byte(s)\n", image.Size) fmt.Printf(" Image Replication Type: %s\n", image.ReplicationType) fmt.Printf(" Image Replication Progress: %s\n", image.ReplicationProgress) fmt.Printf(" Image Seeding Progress: %s\n", image.SeedingProgress) fmt.Printf(" Settings: \n") for _, setting := range image.Settings { fmt.Printf(" %s : %s\n", setting.Name, setting.DefaultValue) } } return nil }
// Sends a show resource-ticket task to client based on the cli.Context // Returns an error if one occurred func showResourceTicket(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "resource-ticket show <name> [<options>]") if err != nil { return err } name := c.Args().First() tenantName := c.String("tenant") client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } tenant, err := verifyTenant(tenantName) if err != nil { return err } rt, err := findResourceTicket(tenant.ID, name) if err != nil { return err } if c.GlobalIsSet("non-interactive") { usage := quotaLineItemListToString(rt.Usage) limits := quotaLineItemListToString(rt.Limits) fmt.Printf("%s\t%s\t%s\t%s\n", rt.Name, rt.ID, limits, usage) } else if utils.NeedsFormatting(c) { utils.FormatObject(rt, w, c) } else { w := new(tabwriter.Writer) w.Init(os.Stdout, 4, 4, 2, ' ', 0) fmt.Fprintf(w, "ID\tName\tLimit\tUsage\n") for i := 0; i < len(rt.Limits); i++ { if i == 0 { fmt.Fprintf(w, "%s\t%s\t%s %g %s\t%s %g %s\n", rt.ID, rt.Name, rt.Limits[i].Key, rt.Limits[i].Value, rt.Limits[i].Unit, rt.Usage[i].Key, rt.Usage[i].Value, rt.Usage[i].Unit) } else { fmt.Fprintf(w, "\t\t%s %g %s\t%s %g %s\n", rt.Limits[i].Key, rt.Limits[i].Value, rt.Limits[i].Unit, rt.Usage[i].Key, rt.Usage[i].Value, rt.Usage[i].Unit) } } err := w.Flush() if err != nil { return err } } return nil }
// Sends a create availability-zone task to client based on the cli.Context // Returns an error if one occurred func createAvailabilityZone(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "availability-zone create [<options>]") if err != nil { return err } name := c.String("name") if !utils.IsNonInteractive(c) { var err error name, err = askForInput("AvailabilityZone name: ", name) if err != nil { return err } } if len(name) == 0 { return fmt.Errorf("Please provide availability zone name") } azSpec := &photon.AvailabilityZoneCreateSpec{ Name: name, } client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } createTask, err := client.Esxclient.AvailabilityZones.Create(azSpec) if err != nil { return err } id, err := waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { zone, err := client.Esxclient.AvailabilityZones.Get(id) if err != nil { return err } utils.FormatObject(zone, w, c) } return nil }
// Show host info with the specified host ID, returns an error if one occurred func showHost(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "host show <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } host, err := client.Esxclient.Hosts.Get(id) if err != nil { return err } if c.GlobalIsSet("non-interactive") { tag := strings.Trim(fmt.Sprint(host.Tags), "[]") scriptTag := strings.Replace(tag, " ", ",", -1) metadata := strings.Trim(strings.TrimLeft(fmt.Sprint(host.Metadata), "map"), "[]") scriptMetadata := strings.Replace(metadata, " ", ",", -1) fmt.Printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", host.ID, host.Username, host.Password, host.Address, scriptTag, host.State, scriptMetadata, host.AvailabilityZone, host.EsxVersion) } else if utils.NeedsFormatting(c) { utils.FormatObject(host, w, c) } else { fmt.Println("Host ID: ", host.ID) fmt.Println(" Username: "******" Password: "******" IP: ", host.Address) fmt.Println(" Tags: ", host.Tags) fmt.Println(" State: ", host.State) fmt.Println(" Metadata: ", host.Metadata) fmt.Println(" AvailabilityZone: ", host.AvailabilityZone) fmt.Println(" Version: ", host.EsxVersion) } return nil }
func showTenant(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "tenant show <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } tenant, err := client.Esxclient.Tenants.Get(id) if err != nil { return err } if c.GlobalIsSet("non-interactive") { securityGroups := []string{} for _, s := range tenant.SecurityGroups { securityGroups = append(securityGroups, fmt.Sprintf("%s:%t", s.Name, s.Inherited)) } scriptSecurityGroups := strings.Join(securityGroups, ",") fmt.Printf("%s\t%s\t%s\n", tenant.ID, tenant.Name, scriptSecurityGroups) } else if utils.NeedsFormatting(c) { utils.FormatObject(tenant, w, c) } else { fmt.Println("Tenant ID: ", tenant.ID) fmt.Println(" Name: ", tenant.Name) for i, s := range tenant.SecurityGroups { fmt.Printf(" SecurityGroups %d:\n", i+1) fmt.Println(" Name: ", s.Name) fmt.Println(" Inherited: ", s.Inherited) } } return nil }
// Sends a get project task to client based on the config file // Returns an error if one occurred func getProject(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "project get") if err != nil { return err } config, err := cf.LoadConfig() if err != nil { return err } project := config.Project if project == nil { return fmt.Errorf("Error: No Project selected\n") } if c.GlobalIsSet("non-interactive") { fmt.Printf("%s\t%s\n", project.ID, project.Name) } else if utils.NeedsFormatting(c) { utils.FormatObject(project, w, c) } else { fmt.Printf("Current project is '%s' with ID %s\n", project.ID, project.Name) } return nil }
// Outputs the set tenant otherwise informs user it is not set func getTenant(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "tenant get") if err != nil { return err } config, err := cf.LoadConfig() if err != nil { return err } tenant := config.Tenant if tenant == nil { fmt.Printf("No tenant selected\n") } else { if c.GlobalIsSet("non-interactive") { fmt.Printf("%s\t%s\n", tenant.ID, tenant.Name) } else if utils.NeedsFormatting(c) { utils.FormatObject(tenant, w, c) } else { fmt.Printf("Current tenant is '%s' with ID %s\n", tenant.Name, tenant.ID) } } return nil }
// Retrieves information about a flavor func showFlavor(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 1, "flavor show <id>") if err != nil { return err } id := c.Args().First() client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } flavor, err := client.Esxclient.Flavors.Get(id) if err != nil { return err } if c.GlobalIsSet("non-interactive") { costs := quotaLineItemListToString(flavor.Cost) fmt.Printf("%s\t%s\t%s\t%s\t%s\n", flavor.ID, flavor.Name, flavor.Kind, costs, flavor.State) } else if utils.NeedsFormatting(c) { utils.FormatObject(flavor, w, c) } else { costList := []string{} for _, cost := range flavor.Cost { costList = append(costList, fmt.Sprintf("%s %g %s", cost.Key, cost.Value, cost.Unit)) } fmt.Printf("Flavor ID: %s\n", flavor.ID) fmt.Printf(" Name: %s\n", flavor.Name) fmt.Printf(" Kind: %s\n", flavor.Kind) fmt.Printf(" Cost: %s\n", costList) fmt.Printf(" State: %s\n", flavor.State) } return nil }
// Sends a create host task to client based on the cli.Context // Returns an error if one occurred func createHost(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "host create [<options>]") if err != nil { return err } username := c.String("username") password := c.String("password") address := c.String("address") availabilityZone := c.String("availability_zone") tags := c.String("tag") metadata := c.String("metadata") deploymentID := c.String("deployment_id") if !utils.IsNonInteractive(c) { var err error username, err = askForInput("Username: "******"Password: "******"Host Address: ", address) if err != nil { return err } tags, err = askForInput("Host Tags (Options [CLOUD,MGMT]. ',' separated): ", tags) if err != nil { return err } metadata, err = askForInput("Host Metadata ({'key':'value'}. required by host of 'MGMT' tag): ", metadata) if err != nil { return err } deploymentID, err = askForInput("Deployment ID: ", deploymentID) if err != nil { return err } } hostSpec := photon.HostCreateSpec{} hostSpec.Username = username hostSpec.Password = password hostSpec.Address = address hostSpec.AvailabilityZone = availabilityZone hostSpec.Tags = regexp.MustCompile(`\s*,\s*`).Split(tags, -1) if len(metadata) == 0 { hostSpec.Metadata = map[string]string{} } else { var data map[string]string err := json.Unmarshal([]byte(metadata), &data) if err != nil { return err } hostSpec.Metadata = data } client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } createTask, err := client.Esxclient.Hosts.Create(&hostSpec, deploymentID) if err != nil { return err } id, err := waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { host, err := client.Esxclient.Hosts.Get(id) if err != nil { return err } utils.FormatObject(host, w, c) } return nil }
// Sends a create tenant task to client based on the cli.Context // Returns an error if one occurred func createTenant(c *cli.Context, w io.Writer) error { if len(c.Args()) > 1 { return fmt.Errorf("Unknown argument: %v", c.Args()[1:]) } name := c.Args().First() securityGroups := c.String("security-groups") if !utils.IsNonInteractive(c) { var err error name, err = askForInput("Tenant name: ", name) if err != nil { return err } securityGroups, err = askForInput("Comma-separated security group names, or hit enter for no security groups): ", securityGroups) if err != nil { return err } } if len(name) == 0 { return fmt.Errorf("Please provide tenant name") } securityGroupList := []string{} if securityGroups != "" { securityGroupList = regexp.MustCompile(`\s*,\s*`).Split(securityGroups, -1) } tenantSpec := &photon.TenantCreateSpec{ Name: name, SecurityGroups: securityGroupList, } var err error client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } createTask, err := client.Esxclient.Tenants.Create(tenantSpec) if err != nil { return err } id, err := waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { tenant, err := client.Esxclient.Tenants.Get(id) if err != nil { return err } utils.FormatObject(tenant, w, c) } 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 }
// Sends a create resource-ticket task to client based on the cli.Context // Returns an error if one occurred func createResourceTicket(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "resource-ticket create [<options>]") if err != nil { return err } tenantName := c.String("tenant") name := c.String("name") limits := c.String("limits") client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } tenant, err := verifyTenant(tenantName) if err != nil { return err } limitsList, err := parseLimitsListFromFlag(limits) if err != nil { return err } if !utils.IsNonInteractive(c) { name, err = askForInput("Resource ticket name: ", name) if err != nil { return err } limitsList, err = askForLimitList(limitsList) if err != nil { return err } } rtSpec := photon.ResourceTicketCreateSpec{} rtSpec.Name = name rtSpec.Limits = limitsList if !utils.IsNonInteractive(c) { fmt.Printf("\nTenant name: %s\n", tenant.Name) fmt.Printf("Creating resource ticket name: %s\n\n", name) fmt.Println("Please make sure limits below are correct:") for i, l := range limitsList { fmt.Printf("%d: %s, %g, %s\n", i+1, l.Key, l.Value, l.Unit) } } if confirmed(utils.IsNonInteractive(c)) { createTask, err := client.Esxclient.Tenants.CreateResourceTicket(tenant.ID, &rtSpec) if err != nil { return err } _, err = waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { options := &photon.ResourceTicketGetOptions{ Name: name, } tickets, err := client.Esxclient.Tenants.GetResourceTickets(tenant.ID, options) if err != nil { return err } utils.FormatObject(tickets.Items[0], w, c) } } else { fmt.Println("OK. Canceled") } return nil }
// Create an image func createImage(c *cli.Context, w io.Writer) error { if len(c.Args()) > 1 { return fmt.Errorf("Unknown argument: %v", c.Args()[1:]) } path := c.Args().First() name := c.String("name") replicationType := c.String("image_replication") if !utils.IsNonInteractive(c) { var err error path, err = askForInput("Image path: ", path) if err != nil { return err } } if len(path) == 0 { return fmt.Errorf("Please provide image path") } path, err := filepath.Abs(path) if err != nil { return err } _, err = os.Stat(path) if err != nil { return fmt.Errorf("No such image file at that path") } if !c.GlobalIsSet("non-interactive") { defaultName := path name, err = askForInput("Image name (default: "+defaultName+"): ", name) if err != nil { return err } if len(name) == 0 { name = defaultName } defaultReplication := "EAGER" replicationType, err = askForInput("Image replication type (default: "+defaultReplication+"): ", replicationType) if err != nil { return err } if len(replicationType) == 0 { replicationType = defaultReplication } } file, err := os.Open(path) if err != nil { return err } client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } options := &photon.ImageCreateOptions{ ReplicationType: replicationType, } if len(replicationType) == 0 { options = nil } uploadTask, err := client.Esxclient.Images.Create(file, name, options) if err != nil { return err } imageID, err := waitOnTaskOperation(uploadTask.ID, c) if err != nil { return err } err = file.Close() if err != nil { return err } if utils.NeedsFormatting(c) { image, err := client.Esxclient.Images.Get(imageID) if err != nil { return err } utils.FormatObject(image, w, c) } return nil }
// Sends a create flavor task to client func createFlavor(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "flavor create [<options>]") if err != nil { return err } name := c.String("name") kind := c.String("kind") cost := c.String("cost") costList, err := parseLimitsListFromFlag(cost) if err != nil { return err } if !utils.IsNonInteractive(c) { name, err = askForInput("Flavor name: ", name) if err != nil { return err } kind, err = askForInput("Flavor kind (persistent-disk, ephemeral-disk, or vm): ", kind) if err != nil { return err } costList, err = askForLimitList(costList) if err != nil { return err } } if len(name) == 0 { return fmt.Errorf("Please provide flavor name") } if len(kind) == 0 || (kind != "persistent-disk" && kind != "ephemeral-disk" && kind != "vm") { return fmt.Errorf("Please provide flavor kind: persistent-disk, ephemeral-disk, or vm") } createSpec := &photon.FlavorCreateSpec{ Name: name, Kind: kind, Cost: costList, } if !utils.IsNonInteractive(c) { fmt.Printf("Creating flavor: '%s', Kind: '%s'\n\n", name, kind) fmt.Printf("Please make sure limits below are correct: \n") for i, l := range costList { fmt.Printf("%d: %s, %g, %s\n", i+1, l.Key, l.Value, l.Unit) } } if confirmed(utils.IsNonInteractive(c)) { var err error client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } createTask, err := client.Esxclient.Flavors.Create(createSpec) if err != nil { return err } flavorId, err := waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { flavor, err := client.Esxclient.Flavors.Get(flavorId) if err != nil { return err } utils.FormatObject(flavor, w, c) } } else { fmt.Println("OK. Canceled") } return nil }
func createNetwork(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "network create [<options>]") if err != nil { return err } name := c.String("name") description := c.String("description") portGroups := c.String("portgroups") if !utils.IsNonInteractive(c) { name, err = askForInput("Network name: ", name) if err != nil { return err } description, err = askForInput("Description of network: ", description) if err != nil { return err } portGroups, err = askForInput("PortGroups of network: ", portGroups) if err != nil { return err } } if len(name) == 0 { return fmt.Errorf("Please provide network name") } if len(portGroups) == 0 { return fmt.Errorf("Please provide portgroups") } portGroupList := regexp.MustCompile(`\s*,\s*`).Split(portGroups, -1) createSpec := &photon.SubnetCreateSpec{ Name: name, Description: description, PortGroups: portGroupList, } client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } task, err := client.Esxclient.Subnets.Create(createSpec) if err != nil { return err } id, err := waitOnTaskOperation(task.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { network, err := client.Esxclient.Subnets.Get(id) if err != nil { return err } utils.FormatObject(network, w, c) } return nil }
// Sends a create project task to client based on the cli.Context // Returns an error if one occurred func createProject(c *cli.Context, w io.Writer) error { err := checkArgNum(c.Args(), 0, "project create [<options>]") if err != nil { return err } tenantName := c.String("tenant") rtName := c.String("resource-ticket") name := c.String("name") limits := c.String("limits") percent := c.Float64("percent") securityGroups := c.String("security-groups") client.Esxclient, err = client.GetClient(utils.IsNonInteractive(c)) if err != nil { return err } tenant, err := verifyTenant(tenantName) if err != nil { return err } var limitsList []photon.QuotaLineItem if c.IsSet("limits") && c.IsSet("percent") { return fmt.Errorf("Error: Can only specify one of '--limits' or '--percent'") } if c.IsSet("limits") { limitsList, err = parseLimitsListFromFlag(limits) if err != nil { return err } } if c.IsSet("percent") { limitsList = []photon.QuotaLineItem{ {Key: "subdivide.percent", Value: percent, Unit: "COUNT"}} } if !utils.IsNonInteractive(c) { name, err = askForInput("Project name: ", name) if err != nil { return err } rtName, err = askForInput("Resource-ticket name: ", rtName) if err != nil { return err } limitsList, err = askForLimitList(limitsList) if err != nil { return err } } projectSpec := photon.ProjectCreateSpec{} projectSpec.Name = name projectSpec.ResourceTicket = photon.ResourceTicketReservation{Name: rtName, Limits: limitsList} if !utils.IsNonInteractive(c) { fmt.Printf("\nTenant name: %s\n", tenant.Name) fmt.Printf("Resource ticket name: %s\n", rtName) fmt.Printf("Creating project name: %s\n\n", name) fmt.Println("Please make sure limits below are correct:") for i, l := range limitsList { fmt.Printf("%d: %s, %g, %s\n", i+1, l.Key, l.Value, l.Unit) } } if confirmed(utils.IsNonInteractive(c)) { if len(securityGroups) > 0 { projectSpec.SecurityGroups = regexp.MustCompile(`\s*,\s*`).Split(securityGroups, -1) } createTask, err := client.Esxclient.Tenants.CreateProject(tenant.ID, &projectSpec) if err != nil { return err } id, err := waitOnTaskOperation(createTask.ID, c) if err != nil { return err } if utils.NeedsFormatting(c) { project, err := client.Esxclient.Projects.Get(id) if err != nil { return err } utils.FormatObject(project, w, c) } } else { fmt.Println("OK. Canceled") } return nil }