Пример #1
0
func doOSList(c *cli.Context) {
	tmplName := ""
	if len(c.Args()) > 0 {
		tmplName = "/" + c.Args().Get(0)
	}

	resp, err := client.SendRequest("GET", "/template"+tmplName, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	if bytes.Contains(resp.Body, []byte("template-list")) {
		tmpls := lib.TemplateList{}
		assert(xml.Unmarshal(resp.Body, &tmpls))
		outputResult(c, tmpls, func(format string) {
			if c.Bool("verbose") {
				lib.PrintXMLStruct(tmpls)
			} else {
				tbl, err := prettytable.NewTable([]prettytable.Column{
					{Header: "TEMPLATE_NAME"}, {Header: "TECHNOLOGY"}, {Header: "TYPE"},
				}...)
				assert(err)
				if c.Bool("no-header") {
					tbl.NoHeader = true
				}
				for _, e := range tmpls.Template {
					tbl.AddRow(e.Name, e.Technology, e.OSType)
				}
				tbl.Print()
			}
		})
	} else {
		tmpl := lib.Template{}
		assert(xml.Unmarshal(resp.Body, &tmpl))
		outputResult(c, tmpl, func(format string) {
			if c.Bool("verbose") {
				lib.PrintXMLStruct(tmpl)
			} else {
				tbl, err := prettytable.NewTable([]prettytable.Column{
					{Header: "TEMPLATE_NAME"}, {Header: "TECHNOLOGY"}, {Header: "TYPE"},
				}...)
				assert(err)
				if c.Bool("no-header") {
					tbl.NoHeader = true
				}
				tbl.AddRow(tmpl.Name, tmpl.Technology, tmpl.OSType)
				tbl.Print()
			}
		})
	}
}
Пример #2
0
func doRecreate(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	path := "/ve/" + vename + "/recreate"
	var q []string
	if len(c.String("template")) > 0 {
		q = append(q, "template="+c.String("template"))
	}
	if c.Bool("drop-apps") {
		q = append(q, "drop-apps=true")
	}
	if len(q) > 0 {
		path += "?" + strings.Join(q, "&")
	}

	resp, err := client.SendRequest("POST", path, nil)
	assert(err)

	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	pwd := lib.PasswordResponse{}
	assert(xml.Unmarshal(resp.Body, &pwd))

	outputResult(c, pwd, func(format string) {
		lib.PrintXMLStruct(pwd)
	})
}
Пример #3
0
func doClone(c *cli.Context) {
	if len(c.Args()) < 2 {
		displayWrongNumOfArgsAndExit(c)
	}
	srcve := c.Args().Get(0)
	destve := c.Args().Get(1)

	path := "/ve/" + srcve + "/clone-to/" + destve
	if c.Int("subscription-id") > 0 {
		path += "/for/" + strconv.Itoa(c.Int("subscription-id"))
	}

	resp, err := client.SendRequest("POST", path, nil)
	assert(err)

	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	pwd := lib.PasswordResponse{}
	assert(xml.Unmarshal(resp.Body, &pwd))

	outputResult(c, pwd, func(format string) {
		lib.PrintXMLStruct(pwd)
	})
}
Пример #4
0
func doLbCreate(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	lbname := c.Args().Get(0)

	path := "/load-balancer"
	if c.Int("subscription-id") > 0 {
		path += "/" + strconv.Itoa(c.Int("subscription-id"))
	}
	path += "/create/" + lbname

	resp, err := client.SendRequest("POST", path, nil)
	assert(err)

	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	pwd := lib.PasswordResponse{}
	assert(xml.Unmarshal(resp.Body, &pwd))

	outputResult(c, pwd, func(format string) {
		lib.PrintXMLStruct(pwd)
	})
}
Пример #5
0
func doHistory(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	path := "/ve/" + vename + "/history/"
	if len(c.String("from")) > 0 && len(c.String("to")) > 0 {
		_, err := lib.ParseArgTimestampFormat(c.String("from"))
		assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

		_, err = lib.ParseArgTimestampFormat(c.String("to"))
		assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

		path += c.String("from") + "/" + c.String("to")
	} else if c.Int("num-records") > 0 {
		path += strconv.Itoa(c.Int("num-records"))
	} else {
		displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments or --num-records flag argument. Please see '" + c.App.Name + " help " + c.Command.Name + "'")
	}

	resp, err := client.SendRequest("GET", path, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	hst := lib.VeHistory{}
	assert(xml.Unmarshal(resp.Body, &hst))
	assert(err)

	outputResult(c, hst, func(format string) {
		if c.Bool("verbose") {
			lib.PrintXMLStruct(hst)
		} else {
			tbl, err := prettytable.NewTable([]prettytable.Column{
				{Header: "DATETIME"},
				{Header: "CPU", AlignRight: true},
				{Header: "MEMORY", AlignRight: true},
				{Header: "DISK", AlignRight: true},
				{Header: "BANDWIDTH", AlignRight: true},
				{Header: "PUB_IPS", AlignRight: true},
				{Header: "STATUS"},
			}...)
			assert(err)
			if c.Bool("no-header") {
				tbl.NoHeader = true
			}
			for _, e := range hst.VeSnapshot {
				ts, _ := e.EventTimestamp.MarshalText()
				tbl.AddRow(ts, e.CPU, e.RAM, e.LocalDisk, e.Bandwidth, e.NoOfPublicIP, e.State)
			}
			tbl.Print()
		}
	})
}
Пример #6
0
func doUsage(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	if len(c.String("from")) == 0 || len(c.String("to")) == 0 {
		displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments. Please see '" + c.App.Name + " help " + c.Command.Name + "'")
	}
	path := "/ve/" + vename + "/usage/"

	from, err := lib.ParseArgTimestampFormat(c.String("from"))
	assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

	to, err := lib.ParseArgTimestampFormat(c.String("to"))
	assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

	path += c.String("from") + "/" + c.String("to")

	resp, err := client.SendRequest("GET", path, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	usage := lib.VeResourceUsageReport{}
	assert(xml.Unmarshal(resp.Body, &usage))

	outputResult(c, usage, func(format string) {
		if c.Bool("verbose") {
			lib.PrintXMLStruct(usage)
		} else {
			fmt.Println("RESOURCE USAGE REPORT")
			fmt.Printf("Server: %s\n", usage.VeName)
			fmt.Printf("  From: %s\n", from.Format(lib.DataTimestampFormat))
			fmt.Printf("    To: %s\n\n", to.Format(lib.DataTimestampFormat))

			tbl, err := prettytable.NewTable([]prettytable.Column{
				{Header: "RESOURCE_TYPE"}, {Header: "USAGE", AlignRight: true},
			}...)
			assert(err)
			for _, e := range usage.ResourceUsage {
				name := e.ResourceType
				if len(e.ResourceUsageType) > 0 {
					name += "(" + e.ResourceUsageType + ")"
				}
				tbl.AddRow(name, e.Value)
			}
			for _, e := range usage.VeTraffic {
				tbl.AddRow(e.TrafficType, e.Used)
			}
			tbl.Print()
		}
	})
}
Пример #7
0
func doLbHistory(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	lbname := c.Args().Get(0)

	if c.Int("num-records") <= 0 {
		displayErrorAndExit("This command must be used with --num-records flag and its argument. Please see '" + c.App.Name + " help " + c.Command.Name + "'")
	}
	numRecord := strconv.Itoa(c.Int("num-records"))

	resp, err := client.SendRequest("GET", "/load-balancer/"+lbname+"/history/"+numRecord, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	hst := lib.VeHistory{}
	assert(xml.Unmarshal(resp.Body, &hst))

	outputResult(c, hst, func(format string) {
		if c.Bool("verbose") {
			lib.PrintXMLStruct(hst)
		} else {
			tbl, err := prettytable.NewTable([]prettytable.Column{
				{Header: "DATETIME"},
				{Header: "CPU", AlignRight: true},
				{Header: "MEMORY", AlignRight: true},
				{Header: "DISK", AlignRight: true},
				{Header: "BANDWIDTH", AlignRight: true},
				{Header: "PUB_IPS", AlignRight: true},
				{Header: "STATUS"},
			}...)
			assert(err)
			if c.Bool("no-header") {
				tbl.NoHeader = true
			}
			for _, e := range hst.VeSnapshot {
				ts, _ := e.EventTimestamp.MarshalText()
				tbl.AddRow(ts, e.CPU, e.RAM, e.LocalDisk, e.Bandwidth, e.NoOfPublicIP, e.State)
			}
			tbl.Print()
		}
	})
}
Пример #8
0
func doImageInfo(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	imgname := c.Args().Get(0)

	resp, err := client.SendRequest("GET", "/image/"+imgname, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	img := lib.VeImage{}
	assert(xml.Unmarshal(resp.Body, &img))

	outputResult(c, img, func(format string) {
		lib.PrintXMLStruct(img)
	})
}
Пример #9
0
func doAutoscale(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	resp, err := client.SendRequest("GET", "/ve/"+vename+"/autoscale", nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	autoscale := lib.Autoscale{}
	assert(xml.Unmarshal(resp.Body, &autoscale))

	outputResult(c, autoscale, func(format string) {
		lib.PrintXMLStruct(autoscale)
	})
}
Пример #10
0
func doInitiatingVnc(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	resp, err := client.SendRequest("POST", "/ve/"+vename+"/console", nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	pwd := lib.PasswordResponse{}
	assert(xml.Unmarshal(resp.Body, &pwd))

	outputResult(c, pwd, func(format string) {
		lib.PrintXMLStruct(pwd)
	})
}
Пример #11
0
func doLbInfo(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	lbname := c.Args().Get(0)

	resp, err := client.SendRequest("GET", "/load-balancer/"+lbname, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	lb := lib.LoadBalancer{}
	assert(xml.Unmarshal(resp.Body, &lb))

	outputResult(c, lb, func(format string) {
		if c.Bool("verbose") {
			lib.PrintXMLStruct(lb)
		} else {
			var publicIP lib.IPAddr
			if len(lb.Network.PublicIP) > 0 {
				publicIP = lb.Network.PublicIP[0].Address
			}
			fmt.Println("LOAD BALANCER INFO")
			fmt.Printf("             Name: %s\n", lb.Name)
			fmt.Printf("  Subscription ID: %d\n", lb.SubscriptionID)
			fmt.Printf("Public IP address: %s\n", publicIP)
			fmt.Printf("           Status: %s\n\n", lb.State)
			fmt.Println("BALANCED SERVERS")

			tbl, err := prettytable.NewTable([]prettytable.Column{
				{Header: "NAME"},
				{Header: "IPADDR"},
			}...)
			assert(err)
			for _, e := range lb.UsedBy {
				tbl.AddRow(e.VeName, e.IP)
			}
			tbl.Print()
		}
	})
}
Пример #12
0
func doApplicationInfo(c *cli.Context) {
	if len(c.Args()) < 2 {
		displayWrongNumOfArgsAndExit(c)
	}
	appname := c.Args().Get(0)
	foros := c.Args().Get(1)

	resp, err := client.SendRequest("GET", "/application-template/"+appname+"/"+foros, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	app := lib.ApplicationTemplate{}
	assert(xml.Unmarshal(resp.Body, &app))

	outputResult(c, app, func(format string) {
		lib.PrintXMLStruct(app)
	})
}
Пример #13
0
func doBackupInfo(c *cli.Context) {
	if len(c.Args()) < 2 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)
	backupid := getBackupID(c.Args().Get(1))

	resp, err := client.SendRequest("GET", "/ve/"+vename+"/backup/"+backupid, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	backup := lib.Backup{}
	assert(xml.Unmarshal(resp.Body, &backup))

	outputResult(c, backup, func(format string) {
		lib.PrintXMLStruct(backup)
	})
}
Пример #14
0
func doCreate(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	var ve lib.CreateVe
	if len(c.String("setting-file")) > 0 {
		assert(lib.LoadConfig(c.String("setting-file"), &ve))
		ve.Name = vename
	} else {
		if s, ok := conf.Servers[vename]; ok && s.Spec != nil {
			ve = *s.Spec
		} else {
			cli.ShowCommandHelp(c, c.Command.Name)
			os.Exit(1)
		}
	}

	if len(ve.Hostname) == 0 {
		ve.Hostname = ve.Name
	}

	var b bytes.Buffer
	assert(xml.NewEncoder(&b).Encode(ve))

	resp, err := client.SendRequest("POST", "/ve/", &b)
	assert(err)

	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	pwd := lib.PasswordResponse{}
	assert(xml.Unmarshal(resp.Body, &pwd))

	outputResult(c, pwd, func(format string) {
		lib.PrintXMLStruct(pwd)
	})
}
Пример #15
0
func doAutoscaleCreateUpdate(c *cli.Context) {
	method := "PUT"
	if c.Command.Name == "autoscale-create" {
		method = "POST"
	}

	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	var data lib.AutoscaleData
	if len(c.String("setting-file")) > 0 {
		assert(lib.LoadConfig(c.String("setting-file"), &data))
	} else {
		if s, ok := conf.Servers[vename]; ok && len(s.AutoscaleRule) > 0 {
			data = lib.AutoscaleData{AutoscaleRule: s.AutoscaleRule}
		} else {
			displayErrorAndExit("Couldn't find Autoscale rules for '" + vename + "'")
		}
	}
	var b bytes.Buffer
	assert(xml.NewEncoder(&b).Encode(data))

	resp, err := client.SendRequest(method, "/ve/"+vename+"/autoscale", &b)
	assert(err)

	if resp.StatusCode != 200 {
		displayErrorAndExit(string(resp.Body))
	}

	autoscale := lib.Autoscale{}
	assert(xml.Unmarshal(resp.Body, &autoscale))

	outputResult(c, autoscale, func(format string) {
		lib.PrintXMLStruct(autoscale)
	})
}
Пример #16
0
func doBackupList(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	if len(c.String("from")) == 0 || len(c.String("to")) == 0 {
		displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments. Please see '" + c.App.Name + " help " + c.Command.Name + "'")
	}
	path := "/ve/" + vename + "/backups/"

	from, err := lib.ParseArgTimestampFormat(c.String("from"))
	assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

	to, err := lib.ParseArgTimestampFormat(c.String("to"))
	assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

	path += c.String("from") + "/" + c.String("to")

	resp, err := client.SendRequest("GET", path, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	backups := lib.VeBackups{}
	assert(xml.Unmarshal(resp.Body, &backups))

	outputResult(c, backups, func(format string) {
		if c.Bool("verbose") {
			lib.PrintXMLStruct(backups)
		} else {
			fmt.Println("BACKUP LIST")
			fmt.Printf("Server: %s\n", vename)
			fmt.Printf("  From: %s\n", from.Format(lib.DataTimestampFormat))
			fmt.Printf("    To: %s\n\n", to.Format(lib.DataTimestampFormat))

			tbl, err := prettytable.NewTable([]prettytable.Column{
				{Header: "ID"},
				{Header: "SCHEDULE"},
				{Header: "START"},
				{Header: "END"},
				{Header: "RESULT", AlignRight: true},
				{Header: "SIZE(GB)", AlignRight: true},
				{Header: "NODE"},
				{Header: "DESCRIPTION"},
			}...)
			assert(err)
			for _, e := range backups.Backup {
				schedule := "-"
				if len(e.ScheduleName) > 0 {
					schedule = e.ScheduleName
				}
				result := "fail"
				if e.Successful == true {
					result = "ok"
				}
				size := strconv.FormatFloat(float64(e.BackupSize)/(1<<30), 'f', 3, 64)
				tbl.AddRow(e.CloudBackupID, schedule, e.Started, e.Ended, result, size, e.BackupNodeName, e.Description)
			}
			tbl.Print()
		}
	})
}
Пример #17
0
func doAutoscaleHistory(c *cli.Context) {
	if len(c.Args()) == 0 {
		displayWrongNumOfArgsAndExit(c)
	}
	vename := c.Args().Get(0)

	path := "/ve/" + vename + "/autoscale/history/"
	if len(c.String("from")) > 0 && len(c.String("to")) > 0 {
		_, err := lib.ParseArgTimestampFormat(c.String("from"))
		assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

		_, err = lib.ParseArgTimestampFormat(c.String("to"))
		assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format")

		path += c.String("from") + "/" + c.String("to")
		var q []string
		if c.Int("average-period") > 0 {
			q = append(q, "average-period="+strconv.Itoa(c.Int("average-period")))
		}
		if c.Int("tail") > 0 {
			q = append(q, "tail="+strconv.Itoa(c.Int("tail")))
		}
		if len(q) > 0 {
			path += "?" + strings.Join(q, "&")
		}
	} else if c.Int("num-records") > 0 {
		path += strconv.Itoa(c.Int("num-records"))
	} else {
		displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments or --num-records flag argument. Please see '" + c.App.Name + " help " + c.Command.Name + "'")
	}

	resp, err := client.SendRequest("GET", path, nil)
	assert(err)
	if resp.StatusCode >= 400 {
		displayErrorAndExit(string(resp.Body))
	}

	hst := lib.ResourceConsumptionAndAutoscaleHistory{}
	assert(xml.Unmarshal(resp.Body, &hst))
	assert(err)

	outputResult(c, hst, func(format string) {
		if c.Bool("verbose") {
			lib.PrintXMLStruct(hst)
		} else {
			if len(hst.AutoscaleRule) > 0 {
				fmt.Println("AUTOSCALE RULE HISTORY")
				tbl, err := prettytable.NewTable([]prettytable.Column{
					{Header: "METRIC"},
					{Header: "VERSION", AlignRight: true},
					{Header: "UPDATED"},
					{Header: "DELIVERED"},
					{Header: "DELIVERED-OK"},
					{Header: "MIGRATION"},
					{Header: "RESTART"},
					{Header: "MIN", AlignRight: true},
					{Header: "MAX", AlignRight: true},
					{Header: "STEP", AlignRight: true},
					{Header: "UP_THRES", AlignRight: true},
					{Header: "UP_PERIOD", AlignRight: true},
					{Header: "DOWN_THRES", AlignRight: true},
					{Header: "DOWN_PERIOD", AlignRight: true},
				}...)
				assert(err)
				if c.Bool("no-header") {
					tbl.NoHeader = true
				}
				for _, e := range hst.AutoscaleRule {
					tbl.AddRow(
						e.Metric,
						*e.Version,
						*e.Updated,
						*e.UpdateDelivered,
						*e.UpdateDeliveredOk,
						*e.AllowMigration,
						*e.AllowRestart,
						e.Limits.Min,
						e.Limits.Max,
						e.Limits.Step,
						*e.Thresholds.Up.Threshold,
						e.Thresholds.Up.Period,
						*e.Thresholds.Down.Threshold,
						e.Thresholds.Down.Period,
					)
				}
				tbl.Print()
				fmt.Println()
			}

			fmt.Println("RESOURCE CONSUMPTION")
			tbl, err := prettytable.NewTable([]prettytable.Column{
				{Header: "CPU_USAGE", AlignRight: true},
				{Header: "RAM_USAGE", AlignRight: true},
				{Header: "PRIV_IN", AlignRight: true},
				{Header: "PRIV_OUT", AlignRight: true},
				{Header: "PUB_IN", AlignRight: true},
				{Header: "PUB_OUT", AlignRight: true},
				{Header: "DATETIME"},
				{Header: "CPU", AlignRight: true},
				{Header: "RAM", AlignRight: true},
				{Header: "BANDWIDTH", AlignRight: true},
			}...)
			assert(err)
			if c.Bool("no-header") {
				tbl.NoHeader = true
			}
			for _, e := range hst.ResourceConsumptionSample {
				tbl.AddRow(
					e.CPUUsage,
					e.RAMUsage,
					e.PrivateIncomingTraffic,
					e.PrivateOutgoingTraffic,
					e.PublicIncomingTraffic,
					e.PublicOutgoingTraffic,
					e.PaciTimestamp,
					e.CPU,
					e.RAM,
					e.Bandwidth,
				)
			}
			tbl.Print()
		}
	})
}