porter_app.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. package client
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/porter-dev/porter/api/server/handlers/porter_app"
  6. "github.com/porter-dev/porter/internal/models"
  7. "github.com/porter-dev/porter/api/types"
  8. )
  9. func (c *Client) NewGetPorterApp(
  10. ctx context.Context,
  11. projectID, clusterID uint,
  12. appName string,
  13. ) (*types.PorterApp, error) {
  14. resp := &types.PorterApp{}
  15. err := c.getRequest(
  16. fmt.Sprintf(
  17. "/projects/%d/clusters/%d/applications/%s",
  18. projectID, clusterID, appName,
  19. ),
  20. nil,
  21. resp,
  22. )
  23. return resp, err
  24. }
  25. func (c *Client) NewCreatePorterApp(
  26. ctx context.Context,
  27. projectID, clusterID uint,
  28. appName string,
  29. req *types.CreatePorterAppRequest,
  30. ) (*types.PorterApp, error) {
  31. resp := &types.PorterApp{}
  32. err := c.postRequest(
  33. fmt.Sprintf(
  34. "/projects/%d/clusters/%d/applications/%s",
  35. projectID, clusterID, appName,
  36. ),
  37. req,
  38. resp,
  39. )
  40. return resp, err
  41. }
  42. // NewCreateOrUpdatePorterAppEvent will create a porter app event if one does not exist, or else it will update the existing one if an ID is passed in the object
  43. func (c *Client) NewCreateOrUpdatePorterAppEvent(
  44. ctx context.Context,
  45. projectID, clusterID uint,
  46. appName string,
  47. req *types.CreateOrUpdatePorterAppEventRequest,
  48. ) (types.PorterAppEvent, error) {
  49. resp := &types.PorterAppEvent{}
  50. err := c.postRequest(
  51. fmt.Sprintf(
  52. "/projects/%d/clusters/%d/applications/%s/events",
  53. projectID, clusterID, appName,
  54. ),
  55. req,
  56. resp,
  57. )
  58. return *resp, err
  59. }
  60. // TODO: remove these functions once they are no longer called (check telemetry)
  61. func (c *Client) GetPorterApp(
  62. ctx context.Context,
  63. projectID, clusterID uint,
  64. stackName string,
  65. ) (*types.PorterApp, error) {
  66. resp := &types.PorterApp{}
  67. err := c.getRequest(
  68. fmt.Sprintf(
  69. "/projects/%d/clusters/%d/stacks/%s",
  70. projectID, clusterID, stackName,
  71. ),
  72. nil,
  73. resp,
  74. )
  75. return resp, err
  76. }
  77. func (c *Client) CreatePorterApp(
  78. ctx context.Context,
  79. projectID, clusterID uint,
  80. name string,
  81. req *types.CreatePorterAppRequest,
  82. ) (*types.PorterApp, error) {
  83. resp := &types.PorterApp{}
  84. err := c.postRequest(
  85. fmt.Sprintf(
  86. "/projects/%d/clusters/%d/stacks/%s",
  87. projectID, clusterID, name,
  88. ),
  89. req,
  90. resp,
  91. )
  92. return resp, err
  93. }
  94. // CreateOrUpdatePorterAppEvent will create a porter app event if one does not exist, or else it will update the existing one if an ID is passed in the object
  95. func (c *Client) CreateOrUpdatePorterAppEvent(
  96. ctx context.Context,
  97. projectID, clusterID uint,
  98. name string,
  99. req *types.CreateOrUpdatePorterAppEventRequest,
  100. ) (types.PorterAppEvent, error) {
  101. resp := &types.PorterAppEvent{}
  102. err := c.postRequest(
  103. fmt.Sprintf(
  104. "/projects/%d/clusters/%d/stacks/%s/events",
  105. projectID, clusterID, name,
  106. ),
  107. req,
  108. resp,
  109. )
  110. return *resp, err
  111. }
  112. // ListEnvGroups (List all Env Groups for a given cluster)
  113. func (c *Client) ListEnvGroups(
  114. ctx context.Context,
  115. projectID, clusterID uint,
  116. ) (types.ListEnvironmentGroupsResponse, error) {
  117. resp := &types.ListEnvironmentGroupsResponse{}
  118. err := c.getRequest(
  119. fmt.Sprintf(
  120. "/projects/%d/clusters/%d/environment-groups",
  121. projectID, clusterID,
  122. ),
  123. nil,
  124. resp,
  125. )
  126. return *resp, err
  127. }
  128. // ParseYAML takes in a base64 encoded porter yaml and returns an app proto
  129. func (c *Client) ParseYAML(
  130. ctx context.Context,
  131. projectID, clusterID uint,
  132. b64Yaml string,
  133. appName string,
  134. ) (*porter_app.ParsePorterYAMLToProtoResponse, error) {
  135. resp := &porter_app.ParsePorterYAMLToProtoResponse{}
  136. req := &porter_app.ParsePorterYAMLToProtoRequest{
  137. B64Yaml: b64Yaml,
  138. AppName: appName,
  139. }
  140. err := c.postRequest(
  141. fmt.Sprintf(
  142. "/projects/%d/clusters/%d/apps/parse",
  143. projectID, clusterID,
  144. ),
  145. req,
  146. resp,
  147. )
  148. return resp, err
  149. }
  150. // ValidatePorterApp takes in a base64 encoded app definition that is potentially partial and returns a complete definition
  151. // using any previous app revisions and defaults
  152. func (c *Client) ValidatePorterApp(
  153. ctx context.Context,
  154. projectID, clusterID uint,
  155. appName string,
  156. base64AppProto string,
  157. deploymentTarget string,
  158. commitSHA string,
  159. ) (*porter_app.ValidatePorterAppResponse, error) {
  160. resp := &porter_app.ValidatePorterAppResponse{}
  161. req := &porter_app.ValidatePorterAppRequest{
  162. AppName: appName,
  163. Base64AppProto: base64AppProto,
  164. DeploymentTargetId: deploymentTarget,
  165. CommitSHA: commitSHA,
  166. }
  167. err := c.postRequest(
  168. fmt.Sprintf(
  169. "/projects/%d/clusters/%d/apps/validate",
  170. projectID, clusterID,
  171. ),
  172. req,
  173. resp,
  174. )
  175. return resp, err
  176. }
  177. // ApplyPorterApp takes in a base64 encoded app definition and applies it to the cluster
  178. func (c *Client) ApplyPorterApp(
  179. ctx context.Context,
  180. projectID, clusterID uint,
  181. base64AppProto string,
  182. deploymentTarget string,
  183. appRevisionID string,
  184. forceBuild bool,
  185. ) (*porter_app.ApplyPorterAppResponse, error) {
  186. resp := &porter_app.ApplyPorterAppResponse{}
  187. req := &porter_app.ApplyPorterAppRequest{
  188. Base64AppProto: base64AppProto,
  189. DeploymentTargetId: deploymentTarget,
  190. AppRevisionID: appRevisionID,
  191. ForceBuild: forceBuild,
  192. }
  193. err := c.postRequest(
  194. fmt.Sprintf(
  195. "/projects/%d/clusters/%d/apps/apply",
  196. projectID, clusterID,
  197. ),
  198. req,
  199. resp,
  200. )
  201. return resp, err
  202. }
  203. // DefaultDeploymentTarget returns the default deployment target for a given project and cluster
  204. func (c *Client) DefaultDeploymentTarget(
  205. ctx context.Context,
  206. projectID, clusterID uint,
  207. ) (*porter_app.DefaultDeploymentTargetResponse, error) {
  208. resp := &porter_app.DefaultDeploymentTargetResponse{}
  209. req := &porter_app.DefaultDeploymentTargetRequest{}
  210. err := c.getRequest(
  211. fmt.Sprintf(
  212. "/projects/%d/clusters/%d/default-deployment-target",
  213. projectID, clusterID,
  214. ),
  215. req,
  216. resp,
  217. )
  218. return resp, err
  219. }
  220. // CurrentAppRevision returns the currently deployed app revision for a given project, app name and deployment target
  221. func (c *Client) CurrentAppRevision(
  222. ctx context.Context,
  223. projectID uint, clusterID uint,
  224. appName string, deploymentTarget string,
  225. ) (*porter_app.LatestAppRevisionResponse, error) {
  226. resp := &porter_app.LatestAppRevisionResponse{}
  227. req := &porter_app.LatestAppRevisionRequest{
  228. DeploymentTargetID: deploymentTarget,
  229. }
  230. err := c.getRequest(
  231. fmt.Sprintf(
  232. "/projects/%d/clusters/%d/apps/%s/latest",
  233. projectID, clusterID, appName,
  234. ),
  235. req,
  236. resp,
  237. )
  238. return resp, err
  239. }
  240. // CreatePorterAppDBEntryInput is the input struct to CreatePorterAppDBEntry
  241. type CreatePorterAppDBEntryInput struct {
  242. AppName string
  243. GitRepoName string
  244. GitRepoID uint
  245. GitBranch string
  246. ImageRepository string
  247. PorterYamlPath string
  248. ImageTag string
  249. Local bool
  250. }
  251. // CreatePorterAppDBEntry creates an entry in the porter app
  252. func (c *Client) CreatePorterAppDBEntry(
  253. ctx context.Context,
  254. projectID uint, clusterID uint,
  255. inp CreatePorterAppDBEntryInput,
  256. ) error {
  257. var sourceType porter_app.SourceType
  258. var image *porter_app.Image
  259. if inp.Local {
  260. sourceType = porter_app.SourceType_Local
  261. }
  262. if inp.GitRepoName != "" {
  263. sourceType = porter_app.SourceType_Github
  264. }
  265. if inp.ImageRepository != "" {
  266. sourceType = porter_app.SourceType_DockerRegistry
  267. image = &porter_app.Image{
  268. Repository: inp.ImageRepository,
  269. Tag: inp.ImageTag,
  270. }
  271. }
  272. if sourceType == "" {
  273. return fmt.Errorf("cannot determine source type")
  274. }
  275. req := &porter_app.CreateAppRequest{
  276. Name: inp.AppName,
  277. SourceType: sourceType,
  278. GitBranch: inp.GitBranch,
  279. GitRepoName: inp.GitRepoName,
  280. GitRepoID: inp.GitRepoID,
  281. PorterYamlPath: inp.PorterYamlPath,
  282. Image: image,
  283. }
  284. err := c.postRequest(
  285. fmt.Sprintf(
  286. "/projects/%d/clusters/%d/apps/create",
  287. projectID, clusterID,
  288. ),
  289. req,
  290. &types.PorterApp{},
  291. )
  292. return err
  293. }
  294. // CreateSubdomain returns a subdomain for a given service that point to the ingress-nginx service in the cluster
  295. func (c *Client) CreateSubdomain(
  296. ctx context.Context,
  297. projectID uint, clusterID uint,
  298. appName string, serviceName string,
  299. ) (*porter_app.CreateSubdomainResponse, error) {
  300. resp := &porter_app.CreateSubdomainResponse{}
  301. req := &porter_app.CreateSubdomainRequest{
  302. ServiceName: serviceName,
  303. }
  304. err := c.postRequest(
  305. fmt.Sprintf(
  306. "/projects/%d/clusters/%d/apps/%s/subdomain",
  307. projectID, clusterID, appName,
  308. ),
  309. req,
  310. resp,
  311. )
  312. return resp, err
  313. }
  314. // PredeployStatus checks the current status of a predeploy job for an app revision
  315. func (c *Client) PredeployStatus(
  316. ctx context.Context,
  317. projectID uint, clusterID uint,
  318. appName string, appRevisionId string,
  319. ) (*porter_app.PredeployStatusResponse, error) {
  320. resp := &porter_app.PredeployStatusResponse{}
  321. err := c.getRequest(
  322. fmt.Sprintf(
  323. "/projects/%d/clusters/%d/apps/%s/%s/predeploy-status",
  324. projectID, clusterID, appName, appRevisionId,
  325. ),
  326. nil,
  327. resp,
  328. )
  329. if resp.Status == "" {
  330. return nil, fmt.Errorf("no predeploy status found")
  331. }
  332. return resp, err
  333. }
  334. // UpdateRevisionStatus updates the status of an app revision
  335. func (c *Client) UpdateRevisionStatus(
  336. ctx context.Context,
  337. projectID uint, clusterID uint,
  338. appName string, appRevisionId string,
  339. status models.AppRevisionStatus,
  340. ) (*porter_app.UpdateAppRevisionStatusResponse, error) {
  341. resp := &porter_app.UpdateAppRevisionStatusResponse{}
  342. req := &porter_app.UpdateAppRevisionStatusRequest{
  343. Status: status,
  344. }
  345. err := c.postRequest(
  346. fmt.Sprintf(
  347. "/projects/%d/clusters/%d/apps/%s/revisions/%s",
  348. projectID, clusterID, appName, appRevisionId,
  349. ),
  350. req,
  351. resp,
  352. )
  353. return resp, err
  354. }
  355. // GetBuildEnv returns the build environment for a given app proto
  356. func (c *Client) GetBuildEnv(
  357. ctx context.Context,
  358. projectID uint, clusterID uint,
  359. appName string, appRevisionId string,
  360. ) (*porter_app.GetBuildEnvResponse, error) {
  361. resp := &porter_app.GetBuildEnvResponse{}
  362. err := c.getRequest(
  363. fmt.Sprintf(
  364. "/projects/%d/clusters/%d/apps/%s/revisions/%s/build-env",
  365. projectID, clusterID, appName, appRevisionId,
  366. ),
  367. nil,
  368. resp,
  369. )
  370. return resp, err
  371. }
  372. // CreateOrUpdateAppEnvironment updates the app environment group and creates it if it doesn't exist
  373. func (c *Client) CreateOrUpdateAppEnvironment(
  374. ctx context.Context,
  375. projectID uint, clusterID uint,
  376. appName string,
  377. deploymentTargetID string,
  378. variables map[string]string,
  379. secrets map[string]string,
  380. ) (*porter_app.UpdateAppEnvironmentResponse, error) {
  381. resp := &porter_app.UpdateAppEnvironmentResponse{}
  382. req := &porter_app.UpdateAppEnvironmentRequest{
  383. DeploymentTargetID: deploymentTargetID,
  384. Variables: variables,
  385. Secrets: secrets,
  386. HardUpdate: false,
  387. }
  388. err := c.postRequest(
  389. fmt.Sprintf(
  390. "/projects/%d/clusters/%d/apps/%s/update-environment",
  391. projectID, clusterID, appName,
  392. ),
  393. req,
  394. resp,
  395. )
  396. return resp, err
  397. }