registry_handler.go 9.6 KB

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