registry_handler.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package api
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "strconv"
  6. "time"
  7. "github.com/porter-dev/porter/internal/registry"
  8. "github.com/go-chi/chi"
  9. "github.com/porter-dev/porter/internal/forms"
  10. "github.com/porter-dev/porter/internal/models"
  11. "github.com/aws/aws-sdk-go/service/ecr"
  12. )
  13. // HandleCreateRegistry creates a new registry
  14. func (app *App) HandleCreateRegistry(w http.ResponseWriter, r *http.Request) {
  15. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  16. if err != nil || projID == 0 {
  17. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  18. return
  19. }
  20. form := &forms.CreateRegistry{
  21. ProjectID: uint(projID),
  22. }
  23. // decode from JSON to form value
  24. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  25. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  26. return
  27. }
  28. // validate the form
  29. if err := app.validator.Struct(form); err != nil {
  30. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  31. return
  32. }
  33. // convert the form to a registry
  34. registry, err := form.ToRegistry(*app.Repo)
  35. if err != nil {
  36. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  37. return
  38. }
  39. // handle write to the database
  40. registry, err = app.Repo.Registry.CreateRegistry(registry)
  41. if err != nil {
  42. app.handleErrorDataWrite(err, w)
  43. return
  44. }
  45. app.Logger.Info().Msgf("New registry created: %d", registry.ID)
  46. w.WriteHeader(http.StatusCreated)
  47. regExt := registry.Externalize()
  48. if err := json.NewEncoder(w).Encode(regExt); err != nil {
  49. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  50. return
  51. }
  52. }
  53. // HandleListProjectRegistries returns a list of registries for a project
  54. func (app *App) HandleListProjectRegistries(w http.ResponseWriter, r *http.Request) {
  55. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  56. if err != nil || projID == 0 {
  57. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  58. return
  59. }
  60. regs, err := app.Repo.Registry.ListRegistriesByProjectID(uint(projID))
  61. if err != nil {
  62. app.handleErrorRead(err, ErrProjectDataRead, w)
  63. return
  64. }
  65. extRegs := make([]*models.RegistryExternal, 0)
  66. for _, reg := range regs {
  67. extRegs = append(extRegs, reg.Externalize())
  68. }
  69. w.WriteHeader(http.StatusOK)
  70. if err := json.NewEncoder(w).Encode(extRegs); err != nil {
  71. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  72. return
  73. }
  74. }
  75. // temp -- token response
  76. type RegTokenResponse struct {
  77. Token string `json:"token"`
  78. ExpiresAt *time.Time `json:"expires_at"`
  79. }
  80. // HandleGetProjectRegistryECRToken gets an ECR token for a registry
  81. func (app *App) HandleGetProjectRegistryECRToken(w http.ResponseWriter, r *http.Request) {
  82. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  83. if err != nil || projID == 0 {
  84. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  85. return
  86. }
  87. region := chi.URLParam(r, "region")
  88. if region == "" {
  89. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  90. return
  91. }
  92. // list registries and find one that matches the region
  93. regs, err := app.Repo.Registry.ListRegistriesByProjectID(uint(projID))
  94. var token string
  95. var expiresAt *time.Time
  96. for _, reg := range regs {
  97. if reg.AWSIntegrationID != 0 {
  98. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(reg.AWSIntegrationID)
  99. if err != nil {
  100. app.handleErrorDataRead(err, w)
  101. return
  102. }
  103. if awsInt.AWSRegion == region {
  104. // get the aws integration and session
  105. sess, err := awsInt.GetSession()
  106. if err != nil {
  107. app.handleErrorDataRead(err, w)
  108. return
  109. }
  110. ecrSvc := ecr.New(sess)
  111. output, err := ecrSvc.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
  112. if err != nil {
  113. app.handleErrorDataRead(err, w)
  114. return
  115. }
  116. token = *output.AuthorizationData[0].AuthorizationToken
  117. expiresAt = output.AuthorizationData[0].ExpiresAt
  118. }
  119. }
  120. }
  121. resp := &RegTokenResponse{
  122. Token: token,
  123. ExpiresAt: expiresAt,
  124. }
  125. w.WriteHeader(http.StatusOK)
  126. if err := json.NewEncoder(w).Encode(resp); err != nil {
  127. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  128. return
  129. }
  130. }
  131. type GCRTokenRequestBody struct {
  132. ServerURL string `json:"server_url"`
  133. }
  134. // HandleGetProjectRegistryGCRToken gets a GCR token for a registry
  135. func (app *App) HandleGetProjectRegistryGCRToken(w http.ResponseWriter, r *http.Request) {
  136. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  137. if err != nil || projID == 0 {
  138. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  139. return
  140. }
  141. reqBody := &GCRTokenRequestBody{}
  142. // decode from JSON to form value
  143. if err := json.NewDecoder(r.Body).Decode(reqBody); err != nil {
  144. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  145. return
  146. }
  147. // list registries and find one that matches the region
  148. regs, err := app.Repo.Registry.ListRegistriesByProjectID(uint(projID))
  149. var token string
  150. var expiresAt *time.Time
  151. for _, reg := range regs {
  152. if reg.GCPIntegrationID != 0 && reg.URL == reqBody.ServerURL {
  153. _reg := registry.Registry(*reg)
  154. tokenCache, err := _reg.GetGCRToken(*app.Repo)
  155. if err != nil {
  156. app.handleErrorDataRead(err, w)
  157. return
  158. }
  159. token = string(tokenCache.Token)
  160. expiresAt = &tokenCache.Expiry
  161. }
  162. }
  163. resp := &RegTokenResponse{
  164. Token: token,
  165. ExpiresAt: expiresAt,
  166. }
  167. w.WriteHeader(http.StatusOK)
  168. if err := json.NewEncoder(w).Encode(resp); err != nil {
  169. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  170. return
  171. }
  172. }
  173. // HandleUpdateProjectRegistry updates a registry
  174. func (app *App) HandleUpdateProjectRegistry(w http.ResponseWriter, r *http.Request) {
  175. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  176. if err != nil || projID == 0 {
  177. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  178. return
  179. }
  180. registryID, err := strconv.ParseUint(chi.URLParam(r, "registry_id"), 0, 64)
  181. if err != nil || registryID == 0 {
  182. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  183. return
  184. }
  185. form := &forms.UpdateRegistryForm{
  186. ID: uint(registryID),
  187. }
  188. // decode from JSON to form value
  189. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  190. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  191. return
  192. }
  193. // validate the form
  194. if err := app.validator.Struct(form); err != nil {
  195. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  196. return
  197. }
  198. // convert the form to a registry
  199. registry, err := form.ToRegistry(app.Repo.Registry)
  200. if err != nil {
  201. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  202. return
  203. }
  204. // handle write to the database
  205. registry, err = app.Repo.Registry.UpdateRegistry(registry)
  206. if err != nil {
  207. app.handleErrorDataWrite(err, w)
  208. return
  209. }
  210. w.WriteHeader(http.StatusOK)
  211. regExt := registry.Externalize()
  212. if err := json.NewEncoder(w).Encode(regExt); err != nil {
  213. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  214. return
  215. }
  216. }
  217. // HandleDeleteProjectRegistry handles the deletion of a Registry via the registry ID
  218. func (app *App) HandleDeleteProjectRegistry(w http.ResponseWriter, r *http.Request) {
  219. id, err := strconv.ParseUint(chi.URLParam(r, "registry_id"), 0, 64)
  220. if err != nil || id == 0 {
  221. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  222. return
  223. }
  224. reg, err := app.Repo.Registry.ReadRegistry(uint(id))
  225. if err != nil {
  226. app.handleErrorRead(err, ErrProjectDataRead, w)
  227. return
  228. }
  229. err = app.Repo.Registry.DeleteRegistry(reg)
  230. if err != nil {
  231. app.handleErrorRead(err, ErrProjectDataRead, w)
  232. return
  233. }
  234. w.WriteHeader(http.StatusOK)
  235. }
  236. // HandleListRepositories returns a list of repositories for a given registry
  237. func (app *App) HandleListRepositories(w http.ResponseWriter, r *http.Request) {
  238. regID, err := strconv.ParseUint(chi.URLParam(r, "registry_id"), 0, 64)
  239. if err != nil || regID == 0 {
  240. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  241. return
  242. }
  243. reg, err := app.Repo.Registry.ReadRegistry(uint(regID))
  244. if err != nil {
  245. app.handleErrorRead(err, ErrProjectDataRead, w)
  246. return
  247. }
  248. // cast to a registry from registry package
  249. _reg := registry.Registry(*reg)
  250. regAPI := &_reg
  251. repos, err := regAPI.ListRepositories(*app.Repo)
  252. if err != nil {
  253. app.handleErrorRead(err, ErrProjectDataRead, w)
  254. return
  255. }
  256. w.WriteHeader(http.StatusOK)
  257. if err := json.NewEncoder(w).Encode(repos); err != nil {
  258. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  259. return
  260. }
  261. }
  262. // HandleListImages retrieves a list of repo names
  263. func (app *App) HandleListImages(w http.ResponseWriter, r *http.Request) {
  264. regID, err := strconv.ParseUint(chi.URLParam(r, "registry_id"), 0, 64)
  265. if err != nil || regID == 0 {
  266. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  267. return
  268. }
  269. repoName := chi.URLParam(r, "*")
  270. reg, err := app.Repo.Registry.ReadRegistry(uint(regID))
  271. if err != nil {
  272. app.handleErrorRead(err, ErrProjectDataRead, w)
  273. return
  274. }
  275. // cast to a registry from registry package
  276. _reg := registry.Registry(*reg)
  277. regAPI := &_reg
  278. imgs, err := regAPI.ListImages(repoName, *app.Repo)
  279. if err != nil {
  280. app.handleErrorRead(err, ErrProjectDataRead, w)
  281. return
  282. }
  283. w.WriteHeader(http.StatusOK)
  284. if err := json.NewEncoder(w).Encode(imgs); err != nil {
  285. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  286. return
  287. }
  288. // ref, err := name.ParseReference("gcr.io/google-containers/pause")
  289. // if err != nil {
  290. // fmt.Println(err)
  291. // return
  292. // }
  293. // img, err := remote.Image(ref)
  294. // if err != nil {
  295. // fmt.Println(err)
  296. // return
  297. // }
  298. // fmt.Println(img.Size())
  299. // ctx := r.Context()
  300. // reg, err := name.NewRegistry("index.docker.io")
  301. // if err != nil {
  302. // fmt.Println("fuk")
  303. // fmt.Println(err)
  304. // return
  305. // }
  306. // stuff, err := remote.Catalog(ctx, reg, remote.WithAuthFromKeychain(authn.DefaultKeychain))
  307. // if err != nil {
  308. // fmt.Println(err)
  309. // return
  310. // }
  311. // fmt.Println(stuff[0])
  312. }