1package ecs
2
3import (
4	"net/url"
5	"strconv"
6	"time"
7
8	"github.com/denverdino/aliyungo/common"
9	"github.com/denverdino/aliyungo/util"
10)
11
12// ImageOwnerAlias represents image owner
13type ImageOwnerAlias string
14
15// Constants of image owner
16const (
17	ImageOwnerSystem      = ImageOwnerAlias("system")
18	ImageOwnerSelf        = ImageOwnerAlias("self")
19	ImageOwnerOthers      = ImageOwnerAlias("others")
20	ImageOwnerMarketplace = ImageOwnerAlias("marketplace")
21	ImageOwnerDefault     = ImageOwnerAlias("") //Return the values for system, self, and others
22)
23
24type ImageStatus string
25
26const (
27	ImageStatusAvailable    = ImageStatus("Available")
28	ImageStatusUnAvailable  = ImageStatus("UnAvailable")
29	ImageStatusCreating     = ImageStatus("Creating")
30	ImageStatusCreateFailed = ImageStatus("CreateFailed")
31)
32
33type ImageUsage string
34
35const (
36	ImageUsageInstance = ImageUsage("instance")
37	ImageUsageNone     = ImageUsage("none")
38)
39
40// DescribeImagesArgs repsents arguments to describe images
41type DescribeImagesArgs struct {
42	RegionId        common.Region
43	ImageId         string
44	SnapshotId      string
45	ImageName       string
46	Status          ImageStatus
47	ImageOwnerAlias ImageOwnerAlias
48	common.Pagination
49}
50
51type DescribeImagesResponse struct {
52	common.Response
53	common.PaginationResult
54
55	RegionId common.Region
56	Images   struct {
57		Image []ImageType
58	}
59}
60
61//
62// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&diskdevicemapping
63type DiskDeviceMapping struct {
64	SnapshotId string
65	//Why Size Field is string-type.
66	Size   string
67	Device string
68	//For import images
69	Format    string
70	OSSBucket string
71	OSSObject string
72}
73
74//
75// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&imagetype
76type ImageType struct {
77	ImageId            string
78	ImageVersion       string
79	Architecture       string
80	ImageName          string
81	Description        string
82	Size               int
83	ImageOwnerAlias    string
84	OSName             string
85	OSType             string
86	Platform           string
87	DiskDeviceMappings struct {
88		DiskDeviceMapping []DiskDeviceMapping
89	}
90	ProductCode          string
91	IsSubscribed         bool
92	IsSelfShared         string
93	IsCopied             bool
94	IsSupportIoOptimized bool
95	Progress             string
96	Usage                ImageUsage
97	Status               ImageStatus
98	CreationTime         util.ISO6801Time
99}
100
101// DescribeImages describes images
102//
103// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/image&describeimages
104func (client *Client) DescribeImages(args *DescribeImagesArgs) (images []ImageType, pagination *common.PaginationResult, err error) {
105	response, err := client.DescribeImagesWithRaw(args)
106	if err != nil {
107		return nil, nil, err
108	}
109	return response.Images.Image, &response.PaginationResult, nil
110}
111
112func (client *Client) DescribeImagesWithRaw(args *DescribeImagesArgs) (response *DescribeImagesResponse, err error) {
113	args.Validate()
114	response = &DescribeImagesResponse{}
115	err = client.Invoke("DescribeImages", args, response)
116	if err != nil {
117		return nil, err
118	}
119	return response, nil
120}
121
122// CreateImageArgs repsents arguments to create image
123type CreateImageArgs struct {
124	RegionId     common.Region
125	SnapshotId   string
126	InstanceId   string
127	ImageName    string
128	ImageVersion string
129	Description  string
130	ClientToken  string
131}
132
133type CreateImageResponse struct {
134	common.Response
135
136	ImageId string
137}
138
139// CreateImage creates a new image
140//
141// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/image&createimage
142func (client *Client) CreateImage(args *CreateImageArgs) (imageId string, err error) {
143	response := &CreateImageResponse{}
144	err = client.Invoke("CreateImage", args, &response)
145	if err != nil {
146		return "", err
147	}
148	return response.ImageId, nil
149}
150
151type DeleteImageArgs struct {
152	RegionId common.Region
153	ImageId  string
154}
155
156type DeleteImageResponse struct {
157	common.Response
158}
159
160// DeleteImage deletes Image
161//
162// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/image&deleteimage
163func (client *Client) DeleteImage(regionId common.Region, imageId string) error {
164	args := DeleteImageArgs{
165		RegionId: regionId,
166		ImageId:  imageId,
167	}
168
169	response := &DeleteImageResponse{}
170	return client.Invoke("DeleteImage", &args, &response)
171}
172
173// ModifyImageSharePermission repsents arguments to share image
174type ModifyImageSharePermissionArgs struct {
175	RegionId      common.Region
176	ImageId       string
177	AddAccount    []string
178	RemoveAccount []string
179}
180
181// You can read doc at http://help.aliyun.com/document_detail/ecs/open-api/image/modifyimagesharepermission.html
182func (client *Client) ModifyImageSharePermission(args *ModifyImageSharePermissionArgs) error {
183	req := url.Values{}
184	req.Add("RegionId", string(args.RegionId))
185	req.Add("ImageId", args.ImageId)
186
187	for i, item := range args.AddAccount {
188		req.Add("AddAccount."+strconv.Itoa(i+1), item)
189	}
190	for i, item := range args.RemoveAccount {
191		req.Add("RemoveAccount."+strconv.Itoa(i+1), item)
192	}
193
194	return client.Invoke("ModifyImageSharePermission", req, &common.Response{})
195}
196
197type AccountType struct {
198	AliyunId string
199}
200type ImageSharePermissionResponse struct {
201	common.Response
202	ImageId  string
203	RegionId string
204	Accounts struct {
205		Account []AccountType
206	}
207	TotalCount int
208	PageNumber int
209	PageSize   int
210}
211
212func (client *Client) DescribeImageSharePermission(args *ModifyImageSharePermissionArgs) (*ImageSharePermissionResponse, error) {
213	response := ImageSharePermissionResponse{}
214	err := client.Invoke("DescribeImageSharePermission", args, &response)
215	return &response, err
216}
217
218type CopyImageArgs struct {
219	RegionId               common.Region
220	ImageId                string
221	DestinationRegionId    common.Region
222	DestinationImageName   string
223	DestinationDescription string
224	ClientToken            string
225}
226
227type CopyImageResponse struct {
228	common.Response
229	ImageId string
230}
231
232// You can read doc at https://help.aliyun.com/document_detail/25538.html
233func (client *Client) CopyImage(args *CopyImageArgs) (string, error) {
234	response := &CopyImageResponse{}
235	err := client.Invoke("CopyImage", args, &response)
236	if err != nil {
237		return "", err
238	}
239	return response.ImageId, nil
240}
241
242// ImportImageArgs repsents arguments to import image from oss
243type ImportImageArgs struct {
244	RegionId           common.Region
245	ImageName          string
246	ImageVersion       string
247	Description        string
248	ClientToken        string
249	Architecture       string
250	OSType             string
251	Platform           string
252	DiskDeviceMappings struct {
253		DiskDeviceMapping []DiskDeviceMapping
254	}
255}
256
257func (client *Client) ImportImage(args *ImportImageArgs) (string, error) {
258	response := &CopyImageResponse{}
259	err := client.Invoke("ImportImage", args, &response)
260	if err != nil {
261		return "", err
262	}
263	return response.ImageId, nil
264}
265
266type ImportImageResponse struct {
267	common.Response
268	RegionId     common.Region
269	ImageId      string
270	ImportTaskId string
271}
272
273// Default timeout value for WaitForImageReady method
274const ImageDefaultTimeout = 120
275
276//Wait Image ready
277func (client *Client) WaitForImageReady(regionId common.Region, imageId string, timeout int) error {
278	if timeout <= 0 {
279		timeout = ImageDefaultTimeout
280	}
281	for {
282		args := DescribeImagesArgs{
283			RegionId: regionId,
284			ImageId:  imageId,
285			Status:   ImageStatusCreating,
286		}
287
288		images, _, err := client.DescribeImages(&args)
289		if err != nil {
290			return err
291		}
292		if images == nil || len(images) == 0 {
293			args.Status = ImageStatusAvailable
294			images, _, er := client.DescribeImages(&args)
295			if er == nil && len(images) == 1 {
296				break
297			} else {
298				return common.GetClientErrorFromString("Not found")
299			}
300		}
301		if images[0].Progress == "100%" {
302			break
303		}
304		timeout = timeout - DefaultWaitForInterval
305		if timeout <= 0 {
306			return common.GetClientErrorFromString("Timeout")
307		}
308		time.Sleep(DefaultWaitForInterval * time.Second)
309	}
310	return nil
311}
312
313type CancelCopyImageRequest struct {
314	regionId common.Region
315	ImageId  string
316}
317
318// You can read doc at https://help.aliyun.com/document_detail/25539.html
319func (client *Client) CancelCopyImage(regionId common.Region, imageId string) error {
320	response := &common.Response{}
321	err := client.Invoke("CancelCopyImage", &CancelCopyImageRequest{regionId, imageId}, &response)
322	return err
323}
324