From f6a71a39dde03963f1afa7dcfc9e9d74d9d902f5 Mon Sep 17 00:00:00 2001 From: Zhenguo Niu Date: Wed, 7 Aug 2019 19:05:11 +0800 Subject: [PATCH] Update cloudservers --- .../ecs/{v1_1 => v1}/cloudservers/requests.go | 111 +++----------- openstack/ecs/v1/cloudservers/results.go | 140 ++++++++++++++++++ openstack/ecs/v1/cloudservers/results_job.go | 116 +++++++++++++++ .../ecs/{v1_1 => v1}/cloudservers/urls.go | 8 + openstack/ecs/v1_1/cloudservers/results.go | 119 --------------- 5 files changed, 284 insertions(+), 210 deletions(-) rename openstack/ecs/{v1_1 => v1}/cloudservers/requests.go (54%) create mode 100644 openstack/ecs/v1/cloudservers/results.go create mode 100644 openstack/ecs/v1/cloudservers/results_job.go rename openstack/ecs/{v1_1 => v1}/cloudservers/urls.go (54%) delete mode 100644 openstack/ecs/v1_1/cloudservers/results.go diff --git a/openstack/ecs/v1_1/cloudservers/requests.go b/openstack/ecs/v1/cloudservers/requests.go similarity index 54% rename from openstack/ecs/v1_1/cloudservers/requests.go rename to openstack/ecs/v1/cloudservers/requests.go index c7c4af21d..27cae7c3e 100644 --- a/openstack/ecs/v1_1/cloudservers/requests.go +++ b/openstack/ecs/v1/cloudservers/requests.go @@ -2,114 +2,54 @@ package cloudservers import ( "encoding/base64" - "strings" "github.com/huaweicloud/golangsdk" ) type CreateOpts struct { - //待创建云服务器的系统镜像,需要指定已创建镜像的ID。 ImageRef string `json:"imageRef" required:"true"` - //待创建云服务器的系统规格的ID。 FlavorRef string `json:"flavorRef" required:"true"` - //云服务器名称。 Name string `json:"name" required:"true"` - //创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。更多关于待注入用户数据的信息,请参见用户数据注入。 UserData []byte `json:"-"` // AdminPass sets the root user password. If not set, a randomly-generated // password will be created and returned in the response. AdminPass string `json:"adminPass,omitempty"` - //如果需要使用SSH密钥方式登录云服务器,请指定已创建密钥的名称。 KeyName string `json:"key_name,omitempty"` - //待创建云服务器所属虚拟私有云(简称VPC),需要指定已创建VPC的ID。 VpcId string `json:"vpcid" required:"true"` - //待创建云服务器的网卡信息。 Nics []Nic `json:"nics" required:"true"` - //配置云服务器的弹性IP信息,弹性IP有三种配置方式。 PublicIp *PublicIp `json:"publicip,omitempty"` - //创建云服务器数量。 Count int `json:"count,omitempty"` - //云服务器名称是否允许重名。 IsAutoRename *bool `json:"isAutoRename,omitempty"` - //云服务器对应系统盘相关配置。 RootVolume RootVolume `json:"root_volume" required:"true"` - //云服务器对应数据盘相关配置。每一个数据结构代表一块待创建的数据盘。 DataVolumes []DataVolume `json:"data_volumes,omitempty"` - //云服务器对应安全组信息。 SecurityGroups []SecurityGroup `json:"security_groups,omitempty"` - //待创建云服务器所在的可用分区,需要指定可用分区(AZ)的名称。 AvailabilityZone string `json:"availability_zone" required:"true"` - //创建云服务器附加信息。 ExtendParam *ServerExtendParam `json:"extendparam,omitempty"` - //创建云服务器元数据。 MetaData *MetaData `json:"metadata,omitempty"` - //云服务器调度信息。 SchedulerHints *SchedulerHints `json:"os:scheduler_hints,omitempty"` - //弹性云服务器的标签。 Tags []string `json:"tags,omitempty"` - //弹性云服务器的标签。 ServerTags []ServerTags `json:"server_tags,omitempty"` } -// Create requests a server to be provisioned to the user in the current tenant. -func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (jobId, orderId string, err error) { - var r CreateResult - reqBody, err := opts.ToServerCreateMap() - if err != nil { - return - } - - _, err = client.Post(createURL(client), reqBody, &r.Body, &golangsdk.RequestOpts{OkCodes: []int{200}}) - if err != nil { - return - } - - job, errJob := r.ExtractJob() - order, errOrder := r.ExtractOrder() - if errJob != nil && errOrder != nil { - return - } - - jobId = job.Id - orderId = order.Id - return -} - -// Get job result. -func GetJobResult(client *golangsdk.ServiceClient, id string) (JobResult, error) { - var r JobExecResult - url := jobURL(client, id) - - //把v1.1替换成v1 - url2 := strings.Replace(url, "/v1.1/", "/v1/", 1) - - _, err := client.Get(url2, &r.Body, nil) - if err != nil { - return JobResult{}, err - } - - return r.ExtractJobResult() -} - // CreateOptsBuilder allows extensions to add additional parameters to the // Create request. type CreateOptsBuilder interface { @@ -138,119 +78,88 @@ func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) { } type Nic struct { - //待创建云服务器的网卡信息。 SubnetId string `json:"subnet_id" required:"true"` - //待创建云服务器网卡的IP地址,IPv4格式。 IpAddress string `json:"ip_address,omitempty"` } type PublicIp struct { - //为待创建云服务器分配已有弹性IP时,分配的弹性IP的ID,UUID格式。 Id string `json:"id,omitempty"` - //配置云服务器自动分配弹性IP时,创建弹性IP的配置参数。 Eip *Eip `json:"eip,omitempty"` } type Eip struct { - //弹性IP地址类型。 IpType string `json:"iptype" required:"true"` - //弹性IP地址带宽参数。 BandWidth *BandWidth `json:"bandwidth" required:"true"` - //创建弹性IP的附加信息。 ExtendParam *EipExtendParam `json:"extendparam,omitempty"` } type BandWidth struct { - //带宽(Mbit/s),取值范围为[1,300]。 Size int `json:"size,omitempty"` - //带宽的共享类型。PER,表示独享,WHOLE,表示共享。 ShareType string `json:"sharetype" required:"true"` - //带宽的计费类型。 ChargeMode string `json:"chargemode,omitempty"` - //带宽ID,创建WHOLE类型带宽的弹性IP时可以指定之前的共享带宽创建。 Id string `json:"id,omitempty"` } type EipExtendParam struct { - //公网IP的计费模式。prePaid-预付费,即包年包月;postPaid-后付费,即按需付费; ChargingMode string `json:"chargingMode,omitempty"` } type RootVolume struct { - //云服务器系统盘对应的磁盘类型,需要与系统所提供的磁盘类型相匹配。 VolumeType string `json:"volumetype" required:"true"` - //系统盘大小,容量单位为GB, 输入大小范围为[1,1024]。 Size int `json:"size,omitempty"` - //磁盘的产品信息。 ExtendParam *VolumeExtendParam `json:"extendparam,omitempty"` } type DataVolume struct { - //云服务器数据盘对应的磁盘类型,需要与系统所提供的磁盘类型相匹配。 VolumeType string `json:"volumetype" required:"true"` - //数据盘大小,容量单位为GB,输入大小范围为[10,32768]。 Size int `json:"size" required:"true"` - //创建共享磁盘的信息。 MultiAttach *bool `json:"multiattach,omitempty"` - //数据卷是否使用SCSI锁。 PassThrough *bool `json:"hw:passthrough,omitempty"` - //磁盘的产品信息。 Extendparam *VolumeExtendParam `json:"extendparam,omitempty"` } type VolumeExtendParam struct { - //整机镜像中自带的原始数据盘ID,用于指定整机镜像自带的数据盘信息。 SnapshotId string `json:"snapshotId,omitempty"` } type ServerExtendParam struct { - //计费模式。 ChargingMode string `json:"chargingMode,omitempty"` - //云服务器所在区域ID。 RegionID string `json:"regionID,omitempty"` - //订购周期类型。 PeriodType string `json:"periodType,omitempty"` - //订购周期数。 PeriodNum int `json:"periodNum,omitempty"` - //是否自动续订。 IsAutoRenew string `json:"isAutoRenew,omitempty"` - //下单订购后,是否自动从客户的账户中支付,而不需要客户手动去进行支付。 IsAutoPay string `json:"isAutoPay,omitempty"` - //是否配置虚拟机自动恢复的功能。 SupportAutoRecovery string `json:"support_auto_recovery,omitempty"` } type MetaData struct { - //用户ID。 OpSvcUserId string `json:"op_svc_userid,omitempty"` } type SecurityGroup struct { - //云服务器组ID,UUID格式。 ID string `json:"id" required:"true"` } type SchedulerHints struct { - //云服务器组ID,UUID格式。 Group string `json:"group,omitempty"` } @@ -258,3 +167,23 @@ type ServerTags struct { Key string `json:"key" required:"true"` Value string `json:"value,omitempty"` } + +// Create requests a server to be provisioned to the user in the current tenant. +func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r JobResult) { + reqBody, err := opts.ToServerCreateMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(createURL(client), reqBody, &r.Body, &golangsdk.RequestOpts{OkCodes: []int{200}}) + return +} + +// Get retrieves a particular Server based on its unique ID. +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(getURL(c, id), &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200, 203}, + }) + return +} diff --git a/openstack/ecs/v1/cloudservers/results.go b/openstack/ecs/v1/cloudservers/results.go new file mode 100644 index 000000000..6c9925f97 --- /dev/null +++ b/openstack/ecs/v1/cloudservers/results.go @@ -0,0 +1,140 @@ +package cloudservers + +import ( + "time" + + "github.com/huaweicloud/golangsdk" +) + +type cloudServerResult struct { + golangsdk.Result +} + +type Flavor struct { + Disk string `json:"disk"` + Vcpus string `json:"vcpus"` + RAM string `json:"ram"` + ID string `json:"id"` + Name string `json:"name"` +} + +// Image defines a image struct in details of a server. +type Image struct { + ID string `json:"id"` +} + +type SysTags struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type OsSchedulerHints struct { + Group []string `json:"group"` +} + +// Metadata is only used for method that requests details on a single server, by ID. +// Because metadata struct must be a map. +type Metadata struct { + ChargingMode string `json:"charging_mode"` + OrderID string `json:"metering.order_id"` + ProductID string `json:"metering.product_id"` + VpcID string `json:"vpc_id"` + EcmResStatus string `json:"EcmResStatus"` + ImageID string `json:"metering.image_id"` + Imagetype string `json:"metering.imagetype"` + Resourcespeccode string `json:"metering.resourcespeccode"` + ImageName string `json:"image_name"` + OsBit string `json:"os_bit"` + LockCheckEndpoint string `json:"lock_check_endpoint"` + LockSource string `json:"lock_source"` + LockSourceID string `json:"lock_source_id"` + LockScene string `json:"lock_scene"` + VirtualEnvType string `json:"virtual_env_type"` +} + +type Address struct { + Version string `json:"version"` + Addr string `json:"addr"` + MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` + PortID string `json:"OS-EXT-IPS:port_id"` + Type string `json:"OS-EXT-IPS:type"` +} + +type VolumeAttached struct { + ID string `json:"id"` + DeleteOnTermination string `json:"delete_on_termination"` + BootIndex string `json:"bootIndex"` + Device string `json:"device"` +} + +type SecurityGroups struct { + Name string `json:"name"` +} + +// CloudServer is only used for method that requests details on a single server, by ID. +// Because metadata struct must be a map. +type CloudServer struct { + Status string `json:"status"` + Updated time.Time `json:"updated"` + HostID string `json:"hostId"` + Addresses map[string][]Address `json:"addresses"` + ID string `json:"id"` + Name string `json:"name"` + AccessIPv4 string `json:"accessIPv4"` + AccessIPv6 string `json:"accessIPv6"` + Created time.Time `json:"created"` + Tags []string `json:"tags"` + Description string `json:"description"` + Locked *bool `json:"locked"` + ConfigDrive string `json:"config_drive"` + TenantID string `json:"tenant_id"` + UserID string `json:"user_id"` + HostStatus string `json:"host_status"` + EnterpriseProjectID string `json:"enterprise_project_id"` + SysTags []SysTags `json:"sys_tags"` + Flavor Flavor `json:"flavor"` + Metadata Metadata `json:"metadata"` + SecurityGroups []SecurityGroups `json:"security_groups"` + KeyName string `json:"key_name"` + Image Image `json:"image"` + Progress *int `json:"progress"` + PowerState *int `json:"OS-EXT-STS:power_state"` + VMState string `json:"OS-EXT-STS:vm_state"` + TaskState string `json:"OS-EXT-STS:task_state"` + DiskConfig string `json:"OS-DCF:diskConfig"` + AvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` + LaunchedAt string `json:"OS-SRV-USG:launched_at"` + TerminatedAt string `json:"OS-SRV-USG:terminated_at"` + RootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` + RamdiskID string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` + KernelID string `json:"OS-EXT-SRV-ATTR:kernel_id"` + LaunchIndex *int `json:"OS-EXT-SRV-ATTR:launch_index"` + ReservationID string `json:"OS-EXT-SRV-ATTR:reservation_id"` + Hostname string `json:"OS-EXT-SRV-ATTR:hostname"` + UserData string `json:"OS-EXT-SRV-ATTR:user_data"` + Host string `json:"OS-EXT-SRV-ATTR:host"` + InstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` + HypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` + VolumeAttached []VolumeAttached `json:"os-extended-volumes:volumes_attached"` + OsSchedulerHints OsSchedulerHints `json:"os:scheduler_hints"` +} + +// NewCloudServer defines the response from details on a single server, by ID. +type NewCloudServer struct { + CloudServer + Metadata map[string]string `json:"metadata"` +} + +// GetResult is the response from a Get operation. Call its Extract +// method to interpret it as a Server. +type GetResult struct { + cloudServerResult +} + +func (r GetResult) Extract() (*CloudServer, error) { + var s struct { + Server *CloudServer `json:"server"` + } + err := r.ExtractInto(&s) + return s.Server, err +} diff --git a/openstack/ecs/v1/cloudservers/results_job.go b/openstack/ecs/v1/cloudservers/results_job.go new file mode 100644 index 000000000..95a13577b --- /dev/null +++ b/openstack/ecs/v1/cloudservers/results_job.go @@ -0,0 +1,116 @@ +package cloudservers + +import ( + "fmt" + "time" + + "github.com/huaweicloud/golangsdk" +) + +type JobResponse struct { + JobID string `json:"job_id"` +} + +type JobStatus struct { + Status string `json:"status"` + Entities JobEntity `json:"entities"` + JobID string `json:"job_id"` + JobType string `json:"job_type"` + BeginTime string `json:"begin_time"` + EndTime string `json:"end_time"` + ErrorCode string `json:"error_code"` + FailReason string `json:"fail_reason"` +} + +type JobEntity struct { + // Specifies the number of subtasks. + // When no subtask exists, the value of this parameter is 0. + SubJobsTotal int `json:"sub_jobs_total"` + + // Specifies the execution information of a subtask. + // When no subtask exists, the value of this parameter is left blank. + SubJobs []SubJob `json:"sub_jobs"` +} + +type SubJob struct { + // Specifies the task ID. + Id string `json:"job_id"` + + // Task type. + Type string `json:"job_type"` + + //Specifies the task status. + // SUCCESS: indicates the task is successfully executed. + // RUNNING: indicates that the task is in progress. + // FAIL: indicates that the task failed. + // INIT: indicates that the task is being initialized. + Status string `json:"status"` + + // Specifies the time when the task started. + BeginTime string `json:"begin_time"` + + // Specifies the time when the task finished. + EndTime string `json:"end_time"` + + // Specifies the returned error code when the task execution fails. + ErrorCode string `json:"error_code"` + + // Specifies the cause of the task execution failure. + FailReason string `json:"fail_reason"` + + // Specifies the object of the task. + Entities map[string]string `json:"entities"` +} + +type JobResult struct { + golangsdk.Result +} + +func (r JobResult) ExtractJobResponse() (*JobResponse, error) { + job := new(JobResponse) + err := r.ExtractInto(job) + return job, err +} + +func (r JobResult) ExtractJobStatus() (*JobStatus, error) { + job := new(JobStatus) + err := r.ExtractInto(job) + return job, err +} + +func WaitForJobSuccess(client *golangsdk.ServiceClient, secs int, jobID string) error { + return golangsdk.WaitFor(secs, func() (bool, error) { + job := new(JobStatus) + _, err := client.Get(jobURL(client, jobID), &job, nil) + time.Sleep(5 * time.Second) + if err != nil { + return false, err + } + + if job.Status == "SUCCESS" { + return true, nil + } + if job.Status == "FAIL" { + err = fmt.Errorf("Job failed with code %s: %s.\n", job.ErrorCode, job.FailReason) + return false, err + } + + return false, nil + }) +} + +func GetJobEntity(client *golangsdk.ServiceClient, jobID string, label string) (interface{}, error) { + job := new(JobStatus) + _, err := client.Get(jobURL(client, jobID), &job, nil) + if err != nil { + return nil, err + } + + if job.Status == "SUCCESS" { + if e := job.Entities.SubJobs[0].Entities[label]; e != "" { + return e, nil + } + } + + return nil, fmt.Errorf("Unexpected conversion error in GetJobEntity.") +} diff --git a/openstack/ecs/v1_1/cloudservers/urls.go b/openstack/ecs/v1/cloudservers/urls.go similarity index 54% rename from openstack/ecs/v1_1/cloudservers/urls.go rename to openstack/ecs/v1/cloudservers/urls.go index 78c77d1e8..e9074c687 100644 --- a/openstack/ecs/v1_1/cloudservers/urls.go +++ b/openstack/ecs/v1/cloudservers/urls.go @@ -6,6 +6,14 @@ func createURL(sc *golangsdk.ServiceClient) string { return sc.ServiceURL("cloudservers") } +func deleteURL(sc *golangsdk.ServiceClient) string { + return sc.ServiceURL("cloudservers", "delete") +} + +func getURL(sc *golangsdk.ServiceClient, serverID string) string { + return sc.ServiceURL("cloudservers", serverID) +} + func jobURL(sc *golangsdk.ServiceClient, jobId string) string { return sc.ServiceURL("jobs", jobId) } diff --git a/openstack/ecs/v1_1/cloudservers/results.go b/openstack/ecs/v1_1/cloudservers/results.go deleted file mode 100644 index 44dc3cea7..000000000 --- a/openstack/ecs/v1_1/cloudservers/results.go +++ /dev/null @@ -1,119 +0,0 @@ -package cloudservers - -import ( - "github.com/huaweicloud/golangsdk" -) - -//执行创建image异步接口时返回的jobid结构 -type Job struct { - // job id of create image - Id string `json:"job_id"` -} - -type Order struct { - Id string `json:"order_id"` -} - -//根据jobId查询job的结构 -type JobResult struct { - //任务ID - Id string `json:"job_id"` - - //任务类型 - Type string `json:"job_type"` - - /*任务状态,目前取值如下: - SUCCESS:表示该任务执行已经结束,任务执行成功。 - FAIL:表示该任务执行已经结束,任务执行失败。 - RUNNING:表示该任务正在执行。 - INIT:表示给任务还未执行,正在初始化。*/ - Status string `json:"status"` - - //任务开始时间 - BeginTime string `json:"begin_time"` - - //任务结束时间 - EndTime string `json:"end_time"` - - //错误码 - ErrorCode string `json:"error_code"` - - //失败原因 - FailReason string `json:"fail_reason"` - - //任务自定义属性。任务正常时,会返回镜像的ID。 - Entities JobEntity `json:"entities"` -} - -type JobEntity struct { - //子任务数量。没有子任务时为0。 - SubJobsTotal int `json:"sub_jobs_total"` - - //每个子任务的执行信息。没有子任务时为空列表。 - SubJobs []SubJob `json:"sub_jobs"` -} - -type SubJob struct { - //任务ID - Id string `json:"job_id"` - - //任务类型 - Type string `json:"job_type"` - - /*任务状态,目前取值如下: - SUCCESS:表示该任务执行已经结束,任务执行成功。 - FAIL:表示该任务执行已经结束,任务执行失败。 - RUNNING:表示该任务正在执行。 - INIT:表示给任务还未执行,正在初始化。*/ - Status string `json:"status"` - - //任务开始时间 - BeginTime string `json:"begin_time"` - - //任务结束时间 - EndTime string `json:"end_time"` - - //错误码 - ErrorCode string `json:"error_code"` - - //失败原因 - FailReason string `json:"fail_reason"` - - //任务自定义属性。任务正常时,会返回镜像的ID。 - Entities *SubJobEntity `json:"entities"` -} - -type SubJobEntity struct { - ServerId string `json:"server_id"` - NicId string `json:"nic_id"` -} - -type commonResult struct { - golangsdk.Result -} - -type CreateResult struct { - commonResult -} - -type JobExecResult struct { - commonResult -} - -func (r commonResult) ExtractJob() (Job, error) { - var j Job - err := r.ExtractInto(&j) - return j, err -} - -func (r commonResult) ExtractOrder() (Order, error) { - var o Order - err := r.ExtractInto(&o) - return o, err -} - -func (r commonResult) ExtractJobResult() (JobResult, error) { - var jr JobResult - err := r.ExtractInto(&jr) - return jr, err -}