mod_images.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package image
  15. import (
  16. "fmt"
  17. "io"
  18. "net/http"
  19. "net/url"
  20. "strconv"
  21. "strings"
  22. "yunion.io/x/jsonutils"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/util/httputils"
  25. "yunion.io/x/pkg/util/printutils"
  26. "yunion.io/x/pkg/utils"
  27. "yunion.io/x/onecloud/pkg/httperrors"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. "yunion.io/x/onecloud/pkg/mcclient/modulebase"
  30. "yunion.io/x/onecloud/pkg/mcclient/modules"
  31. "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
  32. )
  33. type ImageManager struct {
  34. modulebase.ResourceManager
  35. }
  36. const (
  37. IMAGE_META = "X-Image-Meta-"
  38. IMAGE_META_PROPERTY = "X-Image-Meta-Property-"
  39. IMAGE_METADATA = "X-Image-Meta-Metadata"
  40. IMAGE_PROJECT_METADATA = "X-Image-Meta-Project_metadata"
  41. IMAGE_META_COPY_FROM = "x-glance-api-copy-from"
  42. IMAGE_META_COMPRESS_FORMAT = "x-glance-compress-format"
  43. )
  44. func decodeMeta(str string) string {
  45. s, e := url.QueryUnescape(str)
  46. if e == nil && s != str {
  47. return decodeMeta(s)
  48. } else {
  49. return str
  50. }
  51. }
  52. func FetchImageMeta(h http.Header) jsonutils.JSONObject {
  53. meta := jsonutils.NewDict()
  54. meta.Add(jsonutils.NewDict(), "properties")
  55. for k, v := range h {
  56. if k == IMAGE_METADATA && len(v) == 1 {
  57. metadata, _ := jsonutils.Parse([]byte(v[0]))
  58. if metadata != nil {
  59. meta.Add(metadata, "metadata")
  60. }
  61. } else if k == IMAGE_PROJECT_METADATA && len(v) == 1 {
  62. metadata, _ := jsonutils.Parse([]byte(v[0]))
  63. if metadata != nil {
  64. meta.Add(metadata, "project_metadata")
  65. }
  66. } else if strings.HasPrefix(k, IMAGE_META_PROPERTY) {
  67. k := strings.ToLower(k[len(IMAGE_META_PROPERTY):])
  68. meta.Add(jsonutils.NewString(decodeMeta(v[0])), "properties", k)
  69. if strings.IndexByte(k, '-') > 0 {
  70. meta.Add(jsonutils.NewString(decodeMeta(v[0])), "properties", strings.Replace(k, "-", "_", -1))
  71. }
  72. } else if strings.HasPrefix(k, IMAGE_META) {
  73. k := strings.ToLower(k[len(IMAGE_META):])
  74. meta.Add(jsonutils.NewString(decodeMeta(v[0])), k)
  75. if strings.IndexByte(k, '-') > 0 {
  76. meta.Add(jsonutils.NewString(decodeMeta(v[0])), strings.Replace(k, "-", "_", -1))
  77. }
  78. }
  79. }
  80. return meta
  81. }
  82. func (this *ImageManager) GetById(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  83. path := fmt.Sprintf("%s/%s", this.URLPath(), id)
  84. if params != nil {
  85. qs := params.QueryString()
  86. if len(qs) > 0 {
  87. path = fmt.Sprintf("%s?%s", path, qs)
  88. }
  89. }
  90. h, _, e := modulebase.JsonRequest(this.ResourceManager, session, "HEAD", path, nil, nil)
  91. if e != nil {
  92. return nil, e
  93. }
  94. return FetchImageMeta(h), nil
  95. }
  96. func (this *ImageManager) GetByName(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  97. return this.GetById(session, id, params)
  98. }
  99. func (this *ImageManager) Get(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  100. // hack: some GetPropertiesMethod must use HTTP GET action like:
  101. // - GET /images/distinct-field
  102. // hard code this id currently, should found a better solution
  103. if ok, _ := utils.InStringArray(id, []string{"distinct-field", "statistics"}); ok {
  104. return this.ResourceManager.Get(session, id, params)
  105. }
  106. r, e := this.GetById(session, id, params)
  107. if e == nil {
  108. return r, e
  109. }
  110. je, ok := e.(*httputils.JSONClientError)
  111. if ok && je.Code == 404 {
  112. return this.GetByName(session, id, params)
  113. } else {
  114. return nil, e
  115. }
  116. }
  117. func (this *ImageManager) GetId(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (string, error) {
  118. img, e := this.Get(session, id, nil)
  119. if e != nil {
  120. return "", e
  121. }
  122. return img.GetString("id")
  123. }
  124. func (this *ImageManager) BatchGet(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []printutils.SubmitResult {
  125. return modulebase.BatchDo(idlist, func(id string) (jsonutils.JSONObject, error) {
  126. return this.Get(session, id, params)
  127. })
  128. }
  129. func (this *ImageManager) List(session *mcclient.ClientSession, params jsonutils.JSONObject) (*printutils.ListResult, error) {
  130. path := fmt.Sprintf("/%s", this.URLPath())
  131. if params != nil {
  132. details, _ := params.Bool("details")
  133. if details {
  134. path = fmt.Sprintf("%s/detail", path)
  135. }
  136. dictparams, _ := params.(*jsonutils.JSONDict)
  137. dictparams.RemoveIgnoreCase("details")
  138. qs := params.QueryString()
  139. if len(qs) > 0 {
  140. path = fmt.Sprintf("%s?%s", path, qs)
  141. }
  142. }
  143. return modulebase.List(this.ResourceManager, session, path, this.KeywordPlural)
  144. }
  145. func (this *ImageManager) GetPrivateImageCount(s *mcclient.ClientSession, ownerId string, isAdmin bool) (int, error) {
  146. params := jsonutils.NewDict()
  147. params.Add(jsonutils.NewString("none"), "is_public")
  148. params.Add(jsonutils.NewString(ownerId), "owner")
  149. if isAdmin {
  150. params.Add(jsonutils.JSONTrue, "admin")
  151. }
  152. result, err := this.List(s, params)
  153. if err != nil {
  154. return 0, err
  155. }
  156. return len(result.Data), nil
  157. }
  158. type ImageUsageCount struct {
  159. Count int64
  160. Size int64
  161. }
  162. func (this *ImageManager) countUsage(session *mcclient.ClientSession, deleted bool) (map[string]*ImageUsageCount, error) {
  163. var limit int64 = 1000
  164. var offset int64 = 0
  165. ret := make(map[string]*ImageUsageCount)
  166. count := func(ret map[string]*ImageUsageCount, results *printutils.ListResult) {
  167. for _, r := range results.Data {
  168. format, _ := r.GetString("disk_format")
  169. status, _ := r.GetString("status")
  170. img_size, _ := r.Int("size")
  171. if len(format) > 0 {
  172. if _, ok := ret[format]; !ok {
  173. ret[format] = &ImageUsageCount{}
  174. }
  175. ret[format].Size += img_size
  176. ret[format].Count += 1
  177. }
  178. if len(status) > 0 {
  179. if _, ok := ret[status]; !ok {
  180. ret[status] = &ImageUsageCount{}
  181. }
  182. ret[status].Size += img_size
  183. ret[status].Count += 1
  184. }
  185. }
  186. }
  187. query := jsonutils.NewDict()
  188. query.Add(jsonutils.NewInt(limit), "limit")
  189. query.Add(jsonutils.NewInt(offset), "offset")
  190. query.Add(jsonutils.JSONTrue, "admin")
  191. if deleted {
  192. query.Add(jsonutils.NewString("true"), "pending_delete")
  193. }
  194. if result, e := this.List(session, query); e != nil {
  195. return nil, e
  196. } else {
  197. count(ret, result)
  198. offset += limit
  199. for result.Total > int(offset) {
  200. query.Add(jsonutils.NewInt(offset), "offset")
  201. if result, e := this.List(session, query); e != nil {
  202. return nil, e
  203. } else {
  204. count(ret, result)
  205. offset += limit
  206. }
  207. }
  208. }
  209. return ret, nil
  210. }
  211. func (this *ImageManager) GetUsage(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  212. /*body := jsonutils.NewDict()
  213. pendingDelete := jsonutils.NewDict()
  214. for deleted, data := range map[bool]*jsonutils.JSONDict{false: body, true: pendingDelete} {
  215. if ret, err := this.countUsage(session, deleted); err != nil {
  216. return nil, err
  217. } else {
  218. for k, v := range ret {
  219. stat := jsonutils.NewDict()
  220. stat.Add(jsonutils.NewInt(v.Size), "size")
  221. stat.Add(jsonutils.NewInt(v.Count), "count")
  222. data.Add(stat, k)
  223. }
  224. }
  225. }
  226. body.Add(pendingDelete, "pending_delete")
  227. return body, nil
  228. */
  229. return ImageUsages.GetUsage(session, params)
  230. }
  231. func setImageMeta(params jsonutils.JSONObject) (http.Header, error) {
  232. header := http.Header{}
  233. p, e := params.(*jsonutils.JSONDict).GetMap()
  234. if e != nil {
  235. return header, e
  236. }
  237. for k, v := range p {
  238. if k == "copy_from" || k == "properties" || k == "compress_format" {
  239. continue
  240. }
  241. vs, _ := v.GetString()
  242. header.Add(fmt.Sprintf("%s%s", IMAGE_META, utils.Capitalize(k)), vs)
  243. }
  244. properties := map[string]string{}
  245. params.Unmarshal(properties, "properties")
  246. for k, v := range properties {
  247. header.Add(fmt.Sprintf("%s%s", IMAGE_META_PROPERTY, utils.Capitalize(k)), v)
  248. }
  249. return header, nil
  250. }
  251. func (this *ImageManager) ListMemberProjects(s *mcclient.ClientSession, imageId string) (*printutils.ListResult, error) {
  252. result, e := this.ListMemberProjectIds(s, imageId)
  253. if e != nil {
  254. return nil, e
  255. }
  256. for i, member := range result.Data {
  257. projectIdstr, e := member.GetString("member_id")
  258. if e != nil {
  259. return nil, e
  260. }
  261. project, e := identity.Projects.GetById(s, projectIdstr, nil)
  262. if e != nil {
  263. return nil, e
  264. }
  265. result.Data[i] = project
  266. }
  267. return result, nil
  268. }
  269. func (this *ImageManager) ListMemberProjectIds(s *mcclient.ClientSession, imageId string) (*printutils.ListResult, error) {
  270. path := fmt.Sprintf("/%s/%s/members", this.URLPath(), url.PathEscape(imageId))
  271. return modulebase.List(this.ResourceManager, s, path, "members")
  272. }
  273. func (this *ImageManager) AddMembership(s *mcclient.ClientSession, img string, proj string, canShare bool) error {
  274. image, e := Images.Get(s, img, nil)
  275. if e != nil {
  276. return e
  277. }
  278. projectId, e := identity.Projects.GetId(s, proj, nil)
  279. if e != nil {
  280. return e
  281. }
  282. imageOwner, e := image.GetString("owner")
  283. if e != nil {
  284. return e
  285. }
  286. if imageOwner == projectId {
  287. return fmt.Errorf("Project %s owns image %s", proj, img)
  288. }
  289. imageName, e := image.GetString("name")
  290. if e != nil {
  291. return e
  292. }
  293. imageId, e := image.GetString("id")
  294. if e != nil {
  295. return e
  296. }
  297. query := jsonutils.NewDict()
  298. query.Add(jsonutils.NewString(projectId), "owner")
  299. _, e = Images.GetByName(s, imageName, query)
  300. if e != nil {
  301. je, ok := e.(*httputils.JSONClientError)
  302. if ok && je.Code == 404 { // no same name image
  303. sharedImgIds, e := this.ListSharedImageIds(s, projectId)
  304. if e != nil {
  305. return e
  306. }
  307. for _, sharedImgId := range sharedImgIds.Data {
  308. sharedImgIdstr, e := sharedImgId.GetString()
  309. if e != nil {
  310. return e
  311. }
  312. if sharedImgIdstr == imageId { // already shared, do update
  313. break
  314. } else {
  315. sharedImg, e := this.GetById(s, sharedImgIdstr, nil)
  316. if e != nil {
  317. return e
  318. }
  319. sharedImgName, e := sharedImg.GetString("name")
  320. if e != nil {
  321. return e
  322. }
  323. if sharedImgName == imageName {
  324. return fmt.Errorf("Name %s conflict with other shared images", imageName)
  325. }
  326. }
  327. }
  328. return this._addMembership(s, imageId, projectId, canShare)
  329. }
  330. }
  331. return fmt.Errorf("Image name conflict")
  332. }
  333. func (this *ImageManager) _addMembership(s *mcclient.ClientSession, image_id string, project_id string, canShare bool) error {
  334. params := jsonutils.NewDict()
  335. // params.Add(jsonutils.NewString(project_id), "member_id")
  336. if canShare {
  337. params.Add(jsonutils.JSONTrue, "member", "can_share")
  338. } else {
  339. params.Add(jsonutils.JSONFalse, "member", "can_share")
  340. }
  341. path := fmt.Sprintf("/%s/%s/members/%s", this.URLPath(), url.PathEscape(image_id), url.PathEscape(project_id))
  342. _, e := modulebase.Put(this.ResourceManager, s, path, params, "")
  343. return e
  344. }
  345. func (this *ImageManager) _addMemberships(s *mcclient.ClientSession, image_id string, projectIds []string, canShare bool) error {
  346. memberships := jsonutils.NewArray()
  347. for _, projectId := range projectIds {
  348. member := jsonutils.NewDict()
  349. member.Add(jsonutils.NewString(projectId), "member_id")
  350. if canShare {
  351. member.Add(jsonutils.JSONTrue, "can_share")
  352. } else {
  353. member.Add(jsonutils.JSONFalse, "can_share")
  354. }
  355. memberships.Add(member)
  356. }
  357. params := jsonutils.NewDict()
  358. params.Add(memberships, "memberships")
  359. path := fmt.Sprintf("/%s/%s/members", this.URLPath(), url.PathEscape(image_id))
  360. _, e := modulebase.Put(this.ResourceManager, s, path, params, "")
  361. return e
  362. }
  363. func (this *ImageManager) RemoveMembership(s *mcclient.ClientSession, image string, project string) error {
  364. imgid, e := this.GetId(s, image, nil)
  365. if e != nil {
  366. return e
  367. }
  368. projid, e := identity.Projects.GetId(s, project, nil)
  369. if e != nil {
  370. return e
  371. }
  372. return this._removeMembership(s, imgid, projid)
  373. }
  374. func (this *ImageManager) _removeMembership(s *mcclient.ClientSession, image_id string, project_id string) error {
  375. path := fmt.Sprintf("/%s/%s/members/%s", this.URLPath(), url.PathEscape(image_id), url.PathEscape(project_id))
  376. _, e := modulebase.Delete(this.ResourceManager, s, path, nil, "")
  377. return e
  378. }
  379. func (this *ImageManager) ListSharedImageIds(s *mcclient.ClientSession, projectId string) (*printutils.ListResult, error) {
  380. path := fmt.Sprintf("/shared-images/%s", projectId)
  381. // {"shared_images": [{"image_id": "4d82c731-937e-4420-959b-de9c213efd2b", "can_share": false}]}
  382. return modulebase.List(this.ResourceManager, s, path, "shared_images")
  383. }
  384. func (this *ImageManager) ListSharedImages(s *mcclient.ClientSession, projectId string) (*printutils.ListResult, error) {
  385. result, e := this.ListSharedImageIds(s, projectId)
  386. if e != nil {
  387. return nil, e
  388. }
  389. for i, imgId := range result.Data {
  390. imgIdstr, e := imgId.GetString("image_id")
  391. if e != nil {
  392. return nil, e
  393. }
  394. img, e := this.GetById(s, imgIdstr, nil)
  395. if e != nil {
  396. return nil, e
  397. }
  398. result.Data[i] = img
  399. }
  400. return result, nil
  401. }
  402. func (this *ImageManager) Create(s *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  403. return this._create(s, params, nil, 0)
  404. }
  405. func (this *ImageManager) Upload(s *mcclient.ClientSession, params jsonutils.JSONObject, body io.Reader, size int64) (jsonutils.JSONObject, error) {
  406. return this._create(s, params, body, size)
  407. }
  408. func (this *ImageManager) _create(s *mcclient.ClientSession, params jsonutils.JSONObject, body io.Reader, size int64) (jsonutils.JSONObject, error) {
  409. imageId, _ := params.GetString("image_id")
  410. path := fmt.Sprintf("/%s", this.URLPath())
  411. method := httputils.POST
  412. if len(imageId) == 0 {
  413. if !params.Contains("name") && !params.Contains("generate_name") {
  414. return nil, httperrors.NewMissingParameterError("name")
  415. }
  416. } else {
  417. path = fmt.Sprintf("/%s/%s", this.URLPath(), imageId)
  418. method = httputils.PUT
  419. }
  420. headers, e := setImageMeta(params)
  421. if e != nil {
  422. return nil, e
  423. }
  424. copyFromUrl, _ := params.GetString("copy_from")
  425. compressFormat, _ := params.GetString("compress_format")
  426. if len(copyFromUrl) != 0 {
  427. if size != 0 {
  428. return nil, fmt.Errorf("Can't use copy_from and upload file at the same time")
  429. }
  430. body = nil
  431. size = 0
  432. headers.Set(IMAGE_META_COPY_FROM, copyFromUrl)
  433. headers.Set(IMAGE_META_COMPRESS_FORMAT, compressFormat)
  434. }
  435. if body != nil {
  436. headers.Add("Content-Type", "application/octet-stream")
  437. if size > 0 {
  438. headers.Add("Content-Length", fmt.Sprintf("%d", size))
  439. }
  440. }
  441. resp, err := modulebase.RawRequest(this.ResourceManager, s, method, path, headers, body)
  442. _, json, err := s.ParseJSONResponse("", resp, err)
  443. if err != nil {
  444. return nil, err
  445. }
  446. return json.Get("image")
  447. }
  448. func (this *ImageManager) Update(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  449. img, err := this.Get(s, id, nil)
  450. if err != nil {
  451. return nil, err
  452. }
  453. idstr, err := img.GetString("id")
  454. if err != nil {
  455. return nil, err
  456. }
  457. properties, _ := img.Get("properties")
  458. if properties != nil {
  459. propDict := properties.(*jsonutils.JSONDict)
  460. propMap, _ := propDict.GetMap()
  461. if propMap != nil {
  462. paramsDict := params.(*jsonutils.JSONDict)
  463. for k, val := range propMap {
  464. if !paramsDict.Contains("properties", k) {
  465. paramsDict.Add(val, "properties", k)
  466. }
  467. }
  468. }
  469. }
  470. return this._update(s, idstr, params, nil)
  471. }
  472. func (this *ImageManager) _update(s *mcclient.ClientSession, id string, params jsonutils.JSONObject, body io.Reader) (jsonutils.JSONObject, error) {
  473. headers, err := setImageMeta(params)
  474. if err != nil {
  475. return nil, err
  476. }
  477. path := fmt.Sprintf("/%s/%s", this.URLPath(), url.PathEscape(id))
  478. resp, err := modulebase.RawRequest(this.ResourceManager, s, "PUT", path, headers, body)
  479. _, json, err := s.ParseJSONResponse("", resp, err)
  480. if err != nil {
  481. return nil, err
  482. }
  483. return json.Get("image")
  484. }
  485. func (this *ImageManager) BatchUpdate(
  486. session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject,
  487. ) []printutils.SubmitResult {
  488. return modulebase.BatchDo(idlist, func(id string) (jsonutils.JSONObject, error) {
  489. var curParams = params.(*jsonutils.JSONDict).Copy()
  490. img, err := this.Get(session, id, nil)
  491. if err != nil {
  492. return nil, err
  493. }
  494. properties, _ := img.Get("properties")
  495. if properties != nil {
  496. propDict := properties.(*jsonutils.JSONDict)
  497. propMap, _ := propDict.GetMap()
  498. if propMap != nil {
  499. for k, val := range propMap {
  500. if !curParams.Contains("properties", k) {
  501. curParams.Add(val, "properties", k)
  502. }
  503. }
  504. }
  505. }
  506. return this._update(session, id, curParams, nil)
  507. })
  508. }
  509. func (this *ImageManager) Download(s *mcclient.ClientSession, id string, format string, torrent bool) (jsonutils.JSONObject, io.Reader, int64, error) {
  510. return this.Download2(s, id, format, torrent)
  511. }
  512. func (this *ImageManager) Download2(s *mcclient.ClientSession, id string, format string, torrent bool) (jsonutils.JSONObject, io.ReadCloser, int64, error) {
  513. query := jsonutils.NewDict()
  514. if len(format) > 0 {
  515. query.Add(jsonutils.NewString(format), "format")
  516. if torrent {
  517. query.Add(jsonutils.JSONTrue, "torrent")
  518. }
  519. }
  520. path := fmt.Sprintf("/%s/%s", this.URLPath(), url.PathEscape(id))
  521. queryString := query.QueryString()
  522. if len(queryString) > 0 {
  523. path = fmt.Sprintf("%s?%s", path, queryString)
  524. }
  525. resp, err := modulebase.RawRequest(this.ResourceManager, s, "GET", path, nil, nil)
  526. if err == nil && resp.StatusCode >= 200 && resp.StatusCode < 300 {
  527. sizeBytes, err := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64)
  528. if err != nil {
  529. log.Errorf("Download image unknown size")
  530. sizeBytes = -1
  531. }
  532. return FetchImageMeta(resp.Header), resp.Body, sizeBytes, nil
  533. } else {
  534. _, _, err = s.ParseJSONResponse("", resp, err)
  535. return nil, nil, -1, err
  536. }
  537. }
  538. var (
  539. Images ImageManager
  540. )
  541. func init() {
  542. Images = ImageManager{modules.NewImageManager("image", "images",
  543. []string{"ID", "Name", "Tags", "Disk_format",
  544. "Size", "Is_public", "Protected", "Is_Standard",
  545. "OS_Type", "OS_Distribution", "OS_version",
  546. "Min_disk", "Min_ram", "Status", "Encrypt_Status",
  547. "Notes", "OS_arch", "Preference",
  548. "OS_Codename", "Description",
  549. "Checksum", "Tenant_Id", "Tenant",
  550. "is_guest_image",
  551. },
  552. []string{"Owner", "Owner_name"})}
  553. modules.Register(&Images)
  554. }
  555. type SImageUsageManager struct {
  556. modulebase.ResourceManager
  557. }
  558. func (this *SImageUsageManager) GetUsage(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  559. url := "/usages"
  560. if params != nil {
  561. query := params.QueryString()
  562. if len(query) > 0 {
  563. url = fmt.Sprintf("%s?%s", url, query)
  564. }
  565. }
  566. return modulebase.Get(this.ResourceManager, session, url, "usage")
  567. }
  568. var (
  569. ImageUsages SImageUsageManager
  570. )
  571. func init() {
  572. ImageUsages = SImageUsageManager{modules.NewImageManager("usage", "usages",
  573. []string{},
  574. []string{})}
  575. // register(&ImageUsages)
  576. }