diff --git a/openstack/bms/v1/baremetalservers/requests.go b/openstack/bms/v1/baremetalservers/requests.go new file mode 100644 index 00000000..d35886f8 --- /dev/null +++ b/openstack/bms/v1/baremetalservers/requests.go @@ -0,0 +1,197 @@ +package baremetalservers + +import ( + "encoding/base64" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/common/tags" +) + +type CreateOpts struct { + ImageRef string `json:"imageRef" required:"true"` + + FlavorRef string `json:"flavorRef" required:"true"` + + Name string `json:"name" required:"true"` + + MetaData MetaData `json:"metadata" required:"true"` + + UserData []byte `json:"-"` + + AdminPass string `json:"adminPass,omitempty"` + + KeyName string `json:"key_name,omitempty"` + + SecurityGroups []SecurityGroup `json:"security_groups,omitempty"` + + Nics []Nic `json:"nics" required:"true"` + + AvailabilityZone string `json:"availability_zone" required:"true"` + + VpcId string `json:"vpcid" required:"true"` + + PublicIp *PublicIp `json:"publicip,omitempty"` + + Count int `json:"count,omitempty"` + + RootVolume *RootVolume `json:"root_volume,omitempty"` + + DataVolumes []DataVolume `json:"data_volumes,omitempty"` + + ExtendParam ServerExtendParam `json:"extendparam" required:"true"` + + SchedulerHints *SchedulerHints `json:"os:scheduler_hints,omitempty"` + + ServerTags []tags.ResourceTag `json:"server_tags,omitempty"` +} + +type MetaData struct { + OpSvcUserId string `json:"op_svc_userid" required:"true"` + BYOL string `json:"BYOL,omitempty"` + AdminPass string `json:"admin_pass,omitempty"` + AgencyName string `json:"agency_name,omitempty"` +} + +type SecurityGroup struct { + ID string `json:"id" required:"true"` +} + +type Nic struct { + SubnetId string `json:"subnet_id" required:"true"` + IpAddress string `json:"ip_address,omitempty"` +} + +type PublicIp struct { + Id string `json:"id,omitempty"` + Eip *Eip `json:"eip,omitempty"` +} + +type RootVolume struct { + VolumeType string `json:"volumetype,omitempty"` + Size int `json:"size,omitempty"` + ClusterID string `json:"cluster_id,omitempty"` + ClusterType string `json:"cluster_type,omitempty"` +} + +type DataVolume struct { + VolumeType string `json:"volumetype" required:"true"` + Size int `json:"size" required:"true"` + Shareable bool `json:"shareable,omitempty"` + ClusterID string `json:"cluster_id,omitempty"` + ClusterType string `json:"cluster_type,omitempty"` +} + +type ServerExtendParam struct { + ChargingMode string `json:"chargingMode,omitempty"` + + 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"` + + EnterpriseProjectId string `json:"enterprise_project_id,omitempty"` +} + +type SchedulerHints struct { + DecBaremetal string `json:"dec_baremetal,omitempty"` +} + +type Eip struct { + IpType string `json:"iptype" required:"true"` + BandWidth BandWidth `json:"bandwidth" required:"true"` + ExtendParam EipExtendParam `json:"extendparam" required:"true"` +} + +type BandWidth struct { + Name string `json:"name,omitempty"` + ShareType string `json:"sharetype" required:"true"` + Id string `json:"id,omitempty"` + Size int `json:"size" required:"true"` + ChargeMode string `json:"chargemode,omitempty"` +} + +type EipExtendParam struct { + ChargingMode string `json:"chargingMode" required:"true"` +} + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToServerCreateMap() (map[string]interface{}, error) +} + +// ToServerCreateMap assembles a request body based on the contents of a +// CreateOpts. +func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + + if opts.UserData != nil { + var userData string + if _, err := base64.StdEncoding.DecodeString(string(opts.UserData)); err != nil { + userData = base64.StdEncoding.EncodeToString(opts.UserData) + } else { + userData = string(opts.UserData) + } + b["user_data"] = &userData + } + + return map[string]interface{}{"server": b}, nil +} + +// CreatePrePaid requests a server to be provisioned to the user in the current tenant. +func CreatePrePaid(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r OrderResult) { + 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}, + }) + return +} + +type UpdateOpts struct { + Name string `json:"name,omitempty"` +} + +type UpdateOptsBuilder interface { + ToServerUpdateMap() (map[string]interface{}, error) +} + +func (opts UpdateOpts) ToServerUpdateMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + + return map[string]interface{}{"server": b}, nil +} + +func Update(client *golangsdk.ServiceClient, id string, ops UpdateOptsBuilder) (r UpdateResult) { + b, err := ops.ToServerUpdateMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Put(putURL(client, id), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} diff --git a/openstack/bms/v1/baremetalservers/results.go b/openstack/bms/v1/baremetalservers/results.go new file mode 100644 index 00000000..d8953492 --- /dev/null +++ b/openstack/bms/v1/baremetalservers/results.go @@ -0,0 +1,141 @@ +package baremetalservers + +import ( + "github.com/huaweicloud/golangsdk" +) + +type cloudServerResult struct { + golangsdk.Result +} + +type Flavor struct { + ID string `json:"id"` + Name string `json:"name"` + Disk string `json:"disk"` + Vcpus string `json:"vcpus"` + RAM string `json:"ram"` +} + +// Image defines a image struct in details of a server. +type Image struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"__os_type"` +} + +type SysTags struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type OsSchedulerHints struct { + DecBaremetal []string `json:"dec_baremetal"` +} + +// 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"` + ImageID string `json:"metering.image_id"` + Imagetype string `json:"metering.imagetype"` + PortList string `json:"baremetalPortIDList"` + Resourcespeccode string `json:"metering.resourcespeccode"` + ResourceType string `json:"metering.resourcetype"` + ImageName string `json:"image_name"` + OpSvcUserId string `json:"op_svc_userid"` + OsType string `json:"os_type"` + BmsSupportEvs string `json:"__bms_support_evs"` + OsBit string `json:"os_bit"` +} + +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 Fault struct { + Message string `json:"message"` + Code int `json:"code"` + Details string `json:"details"` + Created string `json:"created"` +} +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"` + ID string `json:"id"` +} + +// 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 { + ID string `json:"id"` + UserID string `json:"user_id"` + Name string `json:"name"` + TenantID string `json:"tenant_id"` + HostID string `json:"hostId"` + Addresses map[string][]Address `json:"addresses"` + KeyName string `json:"key_name"` + Image Image `json:"image"` + Flavor Flavor `json:"flavor"` + SecurityGroups []SecurityGroups `json:"security_groups"` + AccessIPv4 string `json:"accessIPv4"` + AccessIPv6 string `json:"accessIPv6"` + Status string `json:"status"` + Progress *int `json:"progress"` + ConfigDrive string `json:"config_drive"` + Metadata Metadata `json:"metadata"` + TaskState string `json:"OS-EXT-STS:task_state"` + VMState string `json:"OS-EXT-STS:vm_state"` + Host string `json:"OS-EXT-SRV-ATTR:host"` + InstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` + PowerState *int `json:"OS-EXT-STS:power_state"` + HypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` + AvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` + DiskConfig string `json:"OS-DCF:diskConfig"` + Fault Fault `json:"fault"` + VolumeAttached []VolumeAttached `json:"os-extended-volumes:volumes_attached"` + Description string `json:"description"` + HostStatus string `json:"host_status"` + Hostname string `json:"OS-EXT-SRV-ATTR:hostname"` + ReservationID string `json:"OS-EXT-SRV-ATTR:reservation_id"` + LaunchIndex *int `json:"OS-EXT-SRV-ATTR:launch_index"` + KernelID string `json:"OS-EXT-SRV-ATTR:kernel_id"` + RamdiskID string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` + RootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` + UserData string `json:"OS-EXT-SRV-ATTR:user_data"` + Locked *bool `json:"locked"` + Tags []string `json:"tags"` + OsSchedulerHints OsSchedulerHints `json:"os:scheduler_hints"` + EnterpriseProjectID string `json:"enterprise_project_id"` + SysTags []SysTags `json:"sys_tags"` +} + +// GetResult is the response from a Get operation. Call its Extract +// method to interpret it as a Server. +type GetResult struct { + cloudServerResult +} + +type UpdateResult struct { + cloudServerResult +} + +func (r cloudServerResult) Extract() (*CloudServer, error) { + var s struct { + Server *CloudServer `json:"server"` + } + err := r.ExtractInto(&s) + return s.Server, err +} diff --git a/openstack/bms/v1/baremetalservers/results_job.go b/openstack/bms/v1/baremetalservers/results_job.go new file mode 100644 index 00000000..5bfdb1e9 --- /dev/null +++ b/openstack/bms/v1/baremetalservers/results_job.go @@ -0,0 +1,116 @@ +package baremetalservers + +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/bms/v1/baremetalservers/results_order.go b/openstack/bms/v1/baremetalservers/results_order.go new file mode 100644 index 00000000..8502902d --- /dev/null +++ b/openstack/bms/v1/baremetalservers/results_order.go @@ -0,0 +1,20 @@ +package baremetalservers + +import ( + "github.com/huaweicloud/golangsdk" +) + +type OrderResponse struct { + OrderID string `json:"order_id"` + JobID string `json:"job_id"` +} + +type OrderResult struct { + golangsdk.Result +} + +func (r OrderResult) ExtractOrderResponse() (*OrderResponse, error) { + order := new(OrderResponse) + err := r.ExtractInto(order) + return order, err +} diff --git a/openstack/bms/v1/baremetalservers/urls.go b/openstack/bms/v1/baremetalservers/urls.go new file mode 100644 index 00000000..61e0afd1 --- /dev/null +++ b/openstack/bms/v1/baremetalservers/urls.go @@ -0,0 +1,19 @@ +package baremetalservers + +import "github.com/huaweicloud/golangsdk" + +func createURL(sc *golangsdk.ServiceClient) string { + return sc.ServiceURL("baremetalservers") +} + +func getURL(sc *golangsdk.ServiceClient, serverID string) string { + return sc.ServiceURL("baremetalservers", serverID) +} + +func jobURL(sc *golangsdk.ServiceClient, jobId string) string { + return sc.ServiceURL("jobs", jobId) +} + +func putURL(sc *golangsdk.ServiceClient, serverID string) string { + return sc.ServiceURL("baremetalservers", serverID) +}