registry.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. package api
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "github.com/porter-dev/porter/internal/registry"
  10. "github.com/porter-dev/porter/internal/models"
  11. )
  12. // CreateECRRequest represents the accepted fields for creating
  13. // an ECR registry
  14. type CreateECRRequest struct {
  15. Name string `json:"name"`
  16. AWSIntegrationID uint `json:"aws_integration_id"`
  17. }
  18. // CreateECRResponse is the resulting registry after creation
  19. type CreateECRResponse models.RegistryExternal
  20. // CreateECR creates an Elastic Container Registry integration
  21. func (c *Client) CreateECR(
  22. ctx context.Context,
  23. projectID uint,
  24. createECR *CreateECRRequest,
  25. ) (*CreateECRResponse, error) {
  26. data, err := json.Marshal(createECR)
  27. if err != nil {
  28. return nil, err
  29. }
  30. req, err := http.NewRequest(
  31. "POST",
  32. fmt.Sprintf("%s/projects/%d/registries", c.BaseURL, projectID),
  33. strings.NewReader(string(data)),
  34. )
  35. if err != nil {
  36. return nil, err
  37. }
  38. req = req.WithContext(ctx)
  39. bodyResp := &CreateECRResponse{}
  40. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  41. if httpErr != nil {
  42. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  43. }
  44. return nil, err
  45. }
  46. return bodyResp, nil
  47. }
  48. // CreatePrivateRegistryRequest represents the accepted fields for creating
  49. // a private registry
  50. type CreatePrivateRegistryRequest struct {
  51. Name string `json:"name"`
  52. URL string `json:"url"`
  53. BasicIntegrationID uint `json:"basic_integration_id"`
  54. }
  55. // CreatePrivateRegistryResponse is the resulting registry after creation
  56. type CreatePrivateRegistryResponse models.RegistryExternal
  57. // CreatePrivateRegistry creates a private registry integration
  58. func (c *Client) CreatePrivateRegistry(
  59. ctx context.Context,
  60. projectID uint,
  61. createPR *CreatePrivateRegistryRequest,
  62. ) (*CreatePrivateRegistryResponse, error) {
  63. data, err := json.Marshal(createPR)
  64. if err != nil {
  65. return nil, err
  66. }
  67. req, err := http.NewRequest(
  68. "POST",
  69. fmt.Sprintf("%s/projects/%d/registries", c.BaseURL, projectID),
  70. strings.NewReader(string(data)),
  71. )
  72. if err != nil {
  73. return nil, err
  74. }
  75. req = req.WithContext(ctx)
  76. bodyResp := &CreatePrivateRegistryResponse{}
  77. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  78. if httpErr != nil {
  79. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  80. }
  81. return nil, err
  82. }
  83. return bodyResp, nil
  84. }
  85. // CreateGCRRequest represents the accepted fields for creating
  86. // a GCR registry
  87. type CreateGCRRequest struct {
  88. Name string `json:"name"`
  89. GCPIntegrationID uint `json:"gcp_integration_id"`
  90. URL string `json:"url"`
  91. }
  92. // CreateGCRResponse is the resulting registry after creation
  93. type CreateGCRResponse models.RegistryExternal
  94. // CreateGCR creates an Google Container Registry integration
  95. func (c *Client) CreateGCR(
  96. ctx context.Context,
  97. projectID uint,
  98. createGCR *CreateGCRRequest,
  99. ) (*CreateGCRResponse, error) {
  100. data, err := json.Marshal(createGCR)
  101. if err != nil {
  102. return nil, err
  103. }
  104. req, err := http.NewRequest(
  105. "POST",
  106. fmt.Sprintf("%s/projects/%d/registries", c.BaseURL, projectID),
  107. strings.NewReader(string(data)),
  108. )
  109. if err != nil {
  110. return nil, err
  111. }
  112. req = req.WithContext(ctx)
  113. bodyResp := &CreateGCRResponse{}
  114. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  115. if httpErr != nil {
  116. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  117. }
  118. return nil, err
  119. }
  120. return bodyResp, nil
  121. }
  122. // CreateDOCRRequest represents the accepted fields for creating
  123. // a DOCR registry
  124. type CreateDOCRRequest struct {
  125. Name string `json:"name"`
  126. DOIntegrationID uint `json:"do_integration_id"`
  127. URL string `json:"url"`
  128. }
  129. // CreateDOCRResponse is the resulting registry after creation
  130. type CreateDOCRResponse models.RegistryExternal
  131. // CreateDOCR creates an Digital Ocean Container Registry integration
  132. func (c *Client) CreateDOCR(
  133. ctx context.Context,
  134. projectID uint,
  135. createDOCR *CreateDOCRRequest,
  136. ) (*CreateDOCRResponse, error) {
  137. data, err := json.Marshal(createDOCR)
  138. if err != nil {
  139. return nil, err
  140. }
  141. req, err := http.NewRequest(
  142. "POST",
  143. fmt.Sprintf("%s/projects/%d/registries", c.BaseURL, projectID),
  144. strings.NewReader(string(data)),
  145. )
  146. if err != nil {
  147. return nil, err
  148. }
  149. req = req.WithContext(ctx)
  150. bodyResp := &CreateDOCRResponse{}
  151. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  152. if httpErr != nil {
  153. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  154. }
  155. return nil, err
  156. }
  157. return bodyResp, nil
  158. }
  159. // ListRegistryResponse is the list of registries for a project
  160. type ListRegistryResponse []models.RegistryExternal
  161. // ListRegistries returns a list of registries for a project
  162. func (c *Client) ListRegistries(
  163. ctx context.Context,
  164. projectID uint,
  165. ) (ListRegistryResponse, error) {
  166. req, err := http.NewRequest(
  167. "GET",
  168. fmt.Sprintf("%s/projects/%d/registries", c.BaseURL, projectID),
  169. nil,
  170. )
  171. if err != nil {
  172. return nil, err
  173. }
  174. req = req.WithContext(ctx)
  175. bodyResp := &ListRegistryResponse{}
  176. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  177. if httpErr != nil {
  178. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  179. }
  180. return nil, err
  181. }
  182. return *bodyResp, nil
  183. }
  184. // DeleteProjectRegistry deletes a registry given a project id and registry id
  185. func (c *Client) DeleteProjectRegistry(
  186. ctx context.Context,
  187. projectID uint,
  188. registryID uint,
  189. ) error {
  190. req, err := http.NewRequest(
  191. "DELETE",
  192. fmt.Sprintf("%s/projects/%d/registries/%d", c.BaseURL, projectID, registryID),
  193. nil,
  194. )
  195. if err != nil {
  196. return err
  197. }
  198. req = req.WithContext(ctx)
  199. if httpErr, err := c.sendRequest(req, nil, true); httpErr != nil || err != nil {
  200. if httpErr != nil {
  201. return fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  202. }
  203. return err
  204. }
  205. return nil
  206. }
  207. // GetTokenResponse blah
  208. type GetTokenResponse struct {
  209. Token string `json:"token"`
  210. ExpiresAt *time.Time `json:"expires_at"`
  211. }
  212. // GetECRAuthorizationToken gets an ECR authorization token
  213. func (c *Client) GetECRAuthorizationToken(
  214. ctx context.Context,
  215. projectID uint,
  216. region string,
  217. ) (*GetTokenResponse, error) {
  218. req, err := http.NewRequest(
  219. "GET",
  220. fmt.Sprintf("%s/projects/%d/registries/ecr/%s/token", c.BaseURL, projectID, region),
  221. nil,
  222. )
  223. if err != nil {
  224. return nil, err
  225. }
  226. bodyResp := &GetTokenResponse{}
  227. req = req.WithContext(ctx)
  228. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  229. if httpErr != nil {
  230. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  231. }
  232. return nil, err
  233. }
  234. return bodyResp, nil
  235. }
  236. type GetGCRTokenRequest struct {
  237. ServerURL string `json:"server_url"`
  238. }
  239. // GetGCRAuthorizationToken gets a GCR authorization token
  240. func (c *Client) GetGCRAuthorizationToken(
  241. ctx context.Context,
  242. projectID uint,
  243. gcrRequest *GetGCRTokenRequest,
  244. ) (*GetTokenResponse, error) {
  245. data, err := json.Marshal(gcrRequest)
  246. if err != nil {
  247. return nil, err
  248. }
  249. req, err := http.NewRequest(
  250. "GET",
  251. fmt.Sprintf("%s/projects/%d/registries/gcr/token", c.BaseURL, projectID),
  252. strings.NewReader(string(data)),
  253. )
  254. if err != nil {
  255. return nil, err
  256. }
  257. bodyResp := &GetTokenResponse{}
  258. req = req.WithContext(ctx)
  259. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  260. if httpErr != nil {
  261. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  262. }
  263. return nil, err
  264. }
  265. return bodyResp, nil
  266. }
  267. // GetDockerhubAuthorizationToken gets a Docker Hub authorization token
  268. func (c *Client) GetDockerhubAuthorizationToken(
  269. ctx context.Context,
  270. projectID uint,
  271. ) (*GetTokenResponse, error) {
  272. req, err := http.NewRequest(
  273. "GET",
  274. fmt.Sprintf("%s/projects/%d/registries/dockerhub/token", c.BaseURL, projectID),
  275. nil,
  276. )
  277. if err != nil {
  278. return nil, err
  279. }
  280. bodyResp := &GetTokenResponse{}
  281. req = req.WithContext(ctx)
  282. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  283. if httpErr != nil {
  284. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  285. }
  286. return nil, err
  287. }
  288. return bodyResp, nil
  289. }
  290. type GetDOCRTokenRequest struct {
  291. ServerURL string `json:"server_url"`
  292. }
  293. // GetDOCRAuthorizationToken gets a DOCR authorization token
  294. func (c *Client) GetDOCRAuthorizationToken(
  295. ctx context.Context,
  296. projectID uint,
  297. docrRequest *GetDOCRTokenRequest,
  298. ) (*GetTokenResponse, error) {
  299. data, err := json.Marshal(docrRequest)
  300. if err != nil {
  301. return nil, err
  302. }
  303. req, err := http.NewRequest(
  304. "GET",
  305. fmt.Sprintf("%s/projects/%d/registries/docr/token", c.BaseURL, projectID),
  306. strings.NewReader(string(data)),
  307. )
  308. if err != nil {
  309. return nil, err
  310. }
  311. bodyResp := &GetTokenResponse{}
  312. req = req.WithContext(ctx)
  313. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  314. if httpErr != nil {
  315. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  316. }
  317. return nil, err
  318. }
  319. return bodyResp, nil
  320. }
  321. // ListRegistryRepositoryResponse is the list of repositories in a registry
  322. type ListRegistryRepositoryResponse []registry.Repository
  323. // ListRegistryRepositories lists the repositories in a registry
  324. func (c *Client) ListRegistryRepositories(
  325. ctx context.Context,
  326. projectID uint,
  327. registryID uint,
  328. ) (ListRegistryRepositoryResponse, error) {
  329. req, err := http.NewRequest(
  330. "GET",
  331. fmt.Sprintf("%s/projects/%d/registries/%d/repositories", c.BaseURL, projectID, registryID),
  332. nil,
  333. )
  334. if err != nil {
  335. return nil, err
  336. }
  337. req = req.WithContext(ctx)
  338. bodyResp := &ListRegistryRepositoryResponse{}
  339. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  340. if httpErr != nil {
  341. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  342. }
  343. return nil, err
  344. }
  345. return *bodyResp, nil
  346. }
  347. // ListImagesResponse is the list of images in a repository
  348. type ListImagesResponse []registry.Image
  349. // ListImages lists the images (repository+tag) in a repository
  350. func (c *Client) ListImages(
  351. ctx context.Context,
  352. projectID uint,
  353. registryID uint,
  354. repoName string,
  355. ) (ListImagesResponse, error) {
  356. req, err := http.NewRequest(
  357. "GET",
  358. fmt.Sprintf("%s/projects/%d/registries/%d/repositories/%s", c.BaseURL, projectID, registryID, repoName),
  359. nil,
  360. )
  361. if err != nil {
  362. return nil, err
  363. }
  364. req = req.WithContext(ctx)
  365. bodyResp := &ListImagesResponse{}
  366. if httpErr, err := c.sendRequest(req, bodyResp, true); httpErr != nil || err != nil {
  367. if httpErr != nil {
  368. return nil, fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  369. }
  370. return nil, err
  371. }
  372. return *bodyResp, nil
  373. }
  374. type CreateRepositoryRequest struct {
  375. ImageRepoURI string `json:"image_repo_uri"`
  376. }
  377. // CreateECR creates an Elastic Container Registry integration
  378. func (c *Client) CreateRepository(
  379. ctx context.Context,
  380. projectID, regID uint,
  381. createRepo *CreateRepositoryRequest,
  382. ) error {
  383. data, err := json.Marshal(createRepo)
  384. if err != nil {
  385. return err
  386. }
  387. req, err := http.NewRequest(
  388. "POST",
  389. fmt.Sprintf("%s/projects/%d/registries/%d/repository", c.BaseURL, projectID, regID),
  390. strings.NewReader(string(data)),
  391. )
  392. if err != nil {
  393. return err
  394. }
  395. req = req.WithContext(ctx)
  396. if httpErr, err := c.sendRequest(req, nil, true); httpErr != nil || err != nil {
  397. if httpErr != nil {
  398. return fmt.Errorf("code %d, errors %v", httpErr.Code, httpErr.Errors)
  399. }
  400. return err
  401. }
  402. return nil
  403. }