1package godo 2 3import "fmt" 4 5const imageBasePath = "v2/images" 6 7// ImagesService is an interface for interfacing with the images 8// endpoints of the DigitalOcean API 9// See: https://developers.digitalocean.com/documentation/v2#images 10type ImagesService interface { 11 List(*ListOptions) ([]Image, *Response, error) 12 ListDistribution(opt *ListOptions) ([]Image, *Response, error) 13 ListApplication(opt *ListOptions) ([]Image, *Response, error) 14 ListUser(opt *ListOptions) ([]Image, *Response, error) 15 GetByID(int) (*Image, *Response, error) 16 GetBySlug(string) (*Image, *Response, error) 17 Update(int, *ImageUpdateRequest) (*Image, *Response, error) 18 Delete(int) (*Response, error) 19} 20 21// ImagesServiceOp handles communication with the image related methods of the 22// DigitalOcean API. 23type ImagesServiceOp struct { 24 client *Client 25} 26 27var _ ImagesService = &ImagesServiceOp{} 28 29// Image represents a DigitalOcean Image 30type Image struct { 31 ID int `json:"id,float64,omitempty"` 32 Name string `json:"name,omitempty"` 33 Type string `json:"type,omitempty"` 34 Distribution string `json:"distribution,omitempty"` 35 Slug string `json:"slug,omitempty"` 36 Public bool `json:"public,omitempty"` 37 Regions []string `json:"regions,omitempty"` 38 MinDiskSize int `json:"min_disk_size,omitempty"` 39 Created string `json:"created_at,omitempty"` 40} 41 42// ImageUpdateRequest represents a request to update an image. 43type ImageUpdateRequest struct { 44 Name string `json:"name"` 45} 46 47type imageRoot struct { 48 Image Image 49} 50 51type imagesRoot struct { 52 Images []Image 53 Links *Links `json:"links"` 54} 55 56type listImageOptions struct { 57 Private bool `url:"private,omitempty"` 58 Type string `url:"type,omitempty"` 59} 60 61func (i Image) String() string { 62 return Stringify(i) 63} 64 65// List lists all the images available. 66func (s *ImagesServiceOp) List(opt *ListOptions) ([]Image, *Response, error) { 67 return s.list(opt, nil) 68} 69 70// ListDistribution lists all the distribution images. 71func (s *ImagesServiceOp) ListDistribution(opt *ListOptions) ([]Image, *Response, error) { 72 listOpt := listImageOptions{Type: "distribution"} 73 return s.list(opt, &listOpt) 74} 75 76// ListApplication lists all the application images. 77func (s *ImagesServiceOp) ListApplication(opt *ListOptions) ([]Image, *Response, error) { 78 listOpt := listImageOptions{Type: "application"} 79 return s.list(opt, &listOpt) 80} 81 82// ListUser lists all the user images. 83func (s *ImagesServiceOp) ListUser(opt *ListOptions) ([]Image, *Response, error) { 84 listOpt := listImageOptions{Private: true} 85 return s.list(opt, &listOpt) 86} 87 88// GetByID retrieves an image by id. 89func (s *ImagesServiceOp) GetByID(imageID int) (*Image, *Response, error) { 90 if imageID < 1 { 91 return nil, nil, NewArgError("imageID", "cannot be less than 1") 92 } 93 94 return s.get(interface{}(imageID)) 95} 96 97// GetBySlug retrieves an image by slug. 98func (s *ImagesServiceOp) GetBySlug(slug string) (*Image, *Response, error) { 99 if len(slug) < 1 { 100 return nil, nil, NewArgError("slug", "cannot be blank") 101 } 102 103 return s.get(interface{}(slug)) 104} 105 106// Update an image name. 107func (s *ImagesServiceOp) Update(imageID int, updateRequest *ImageUpdateRequest) (*Image, *Response, error) { 108 if imageID < 1 { 109 return nil, nil, NewArgError("imageID", "cannot be less than 1") 110 } 111 112 if updateRequest == nil { 113 return nil, nil, NewArgError("updateRequest", "cannot be nil") 114 } 115 116 path := fmt.Sprintf("%s/%d", imageBasePath, imageID) 117 req, err := s.client.NewRequest("PUT", path, updateRequest) 118 if err != nil { 119 return nil, nil, err 120 } 121 122 root := new(imageRoot) 123 resp, err := s.client.Do(req, root) 124 if err != nil { 125 return nil, resp, err 126 } 127 128 return &root.Image, resp, err 129} 130 131// Delete an image. 132func (s *ImagesServiceOp) Delete(imageID int) (*Response, error) { 133 if imageID < 1 { 134 return nil, NewArgError("imageID", "cannot be less than 1") 135 } 136 137 path := fmt.Sprintf("%s/%d", imageBasePath, imageID) 138 139 req, err := s.client.NewRequest("DELETE", path, nil) 140 if err != nil { 141 return nil, err 142 } 143 144 resp, err := s.client.Do(req, nil) 145 146 return resp, err 147} 148 149// Helper method for getting an individual image 150func (s *ImagesServiceOp) get(ID interface{}) (*Image, *Response, error) { 151 path := fmt.Sprintf("%s/%v", imageBasePath, ID) 152 153 req, err := s.client.NewRequest("GET", path, nil) 154 if err != nil { 155 return nil, nil, err 156 } 157 158 root := new(imageRoot) 159 resp, err := s.client.Do(req, root) 160 if err != nil { 161 return nil, resp, err 162 } 163 164 return &root.Image, resp, err 165} 166 167// Helper method for listing images 168func (s *ImagesServiceOp) list(opt *ListOptions, listOpt *listImageOptions) ([]Image, *Response, error) { 169 path := imageBasePath 170 path, err := addOptions(path, opt) 171 if err != nil { 172 return nil, nil, err 173 } 174 path, err = addOptions(path, listOpt) 175 if err != nil { 176 return nil, nil, err 177 } 178 179 req, err := s.client.NewRequest("GET", path, nil) 180 if err != nil { 181 return nil, nil, err 182 } 183 184 root := new(imagesRoot) 185 resp, err := s.client.Do(req, root) 186 if err != nil { 187 return nil, resp, err 188 } 189 if l := root.Links; l != nil { 190 resp.Links = l 191 } 192 193 return root.Images, resp, err 194} 195