porter_app.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  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. // ValidatePorterAppInput is the input struct to ValidatePorterApp
  151. type ValidatePorterAppInput struct {
  152. ProjectID uint
  153. ClusterID uint
  154. AppName string
  155. Base64AppProto string
  156. Base64AppOverrides string
  157. DeploymentTarget string
  158. CommitSHA string
  159. }
  160. // ValidatePorterApp takes in a base64 encoded app definition that is potentially partial and returns a complete definition
  161. // using any previous app revisions and defaults
  162. func (c *Client) ValidatePorterApp(
  163. ctx context.Context,
  164. inp ValidatePorterAppInput,
  165. ) (*porter_app.ValidatePorterAppResponse, error) {
  166. resp := &porter_app.ValidatePorterAppResponse{}
  167. req := &porter_app.ValidatePorterAppRequest{
  168. AppName: inp.AppName,
  169. Base64AppProto: inp.Base64AppProto,
  170. Base64AppOverrides: inp.Base64AppOverrides,
  171. DeploymentTargetId: inp.DeploymentTarget,
  172. CommitSHA: inp.CommitSHA,
  173. }
  174. err := c.postRequest(
  175. fmt.Sprintf(
  176. "/projects/%d/clusters/%d/apps/validate",
  177. inp.ProjectID, inp.ClusterID,
  178. ),
  179. req,
  180. resp,
  181. )
  182. return resp, err
  183. }
  184. // ApplyPorterAppInput is the input struct to ApplyPorterApp
  185. type ApplyPorterAppInput struct {
  186. ProjectID uint
  187. ClusterID uint
  188. Base64AppProto string
  189. DeploymentTarget string
  190. AppRevisionID string
  191. ForceBuild bool
  192. Variables map[string]string
  193. Secrets map[string]string
  194. HardEnvUpdate bool
  195. }
  196. // ApplyPorterApp takes in a base64 encoded app definition and applies it to the cluster
  197. func (c *Client) ApplyPorterApp(
  198. ctx context.Context,
  199. inp ApplyPorterAppInput,
  200. ) (*porter_app.ApplyPorterAppResponse, error) {
  201. resp := &porter_app.ApplyPorterAppResponse{}
  202. req := &porter_app.ApplyPorterAppRequest{
  203. Base64AppProto: inp.Base64AppProto,
  204. DeploymentTargetId: inp.DeploymentTarget,
  205. AppRevisionID: inp.AppRevisionID,
  206. ForceBuild: inp.ForceBuild,
  207. Variables: inp.Variables,
  208. Secrets: inp.Secrets,
  209. HardEnvUpdate: inp.HardEnvUpdate,
  210. }
  211. err := c.postRequest(
  212. fmt.Sprintf(
  213. "/projects/%d/clusters/%d/apps/apply",
  214. inp.ProjectID, inp.ClusterID,
  215. ),
  216. req,
  217. resp,
  218. )
  219. return resp, err
  220. }
  221. // DefaultDeploymentTarget returns the default deployment target for a given project and cluster
  222. func (c *Client) DefaultDeploymentTarget(
  223. ctx context.Context,
  224. projectID, clusterID uint,
  225. ) (*porter_app.DefaultDeploymentTargetResponse, error) {
  226. resp := &porter_app.DefaultDeploymentTargetResponse{}
  227. req := &porter_app.DefaultDeploymentTargetRequest{}
  228. err := c.getRequest(
  229. fmt.Sprintf(
  230. "/projects/%d/clusters/%d/default-deployment-target",
  231. projectID, clusterID,
  232. ),
  233. req,
  234. resp,
  235. )
  236. return resp, err
  237. }
  238. // CurrentAppRevision returns the currently deployed app revision for a given project, app name and deployment target
  239. func (c *Client) CurrentAppRevision(
  240. ctx context.Context,
  241. projectID uint, clusterID uint,
  242. appName string, deploymentTarget string,
  243. ) (*porter_app.LatestAppRevisionResponse, error) {
  244. resp := &porter_app.LatestAppRevisionResponse{}
  245. req := &porter_app.LatestAppRevisionRequest{
  246. DeploymentTargetID: deploymentTarget,
  247. }
  248. err := c.getRequest(
  249. fmt.Sprintf(
  250. "/projects/%d/clusters/%d/apps/%s/latest",
  251. projectID, clusterID, appName,
  252. ),
  253. req,
  254. resp,
  255. )
  256. return resp, err
  257. }
  258. // CreatePorterAppDBEntryInput is the input struct to CreatePorterAppDBEntry
  259. type CreatePorterAppDBEntryInput struct {
  260. AppName string
  261. GitRepoName string
  262. GitRepoID uint
  263. GitBranch string
  264. ImageRepository string
  265. PorterYamlPath string
  266. ImageTag string
  267. Local bool
  268. DeploymentTargetID string
  269. }
  270. // CreatePorterAppDBEntry creates an entry in the porter app
  271. func (c *Client) CreatePorterAppDBEntry(
  272. ctx context.Context,
  273. projectID uint, clusterID uint,
  274. inp CreatePorterAppDBEntryInput,
  275. ) error {
  276. var sourceType porter_app.SourceType
  277. var image *porter_app.Image
  278. if inp.Local {
  279. sourceType = porter_app.SourceType_Local
  280. }
  281. if inp.GitRepoName != "" {
  282. sourceType = porter_app.SourceType_Github
  283. }
  284. if inp.ImageRepository != "" {
  285. sourceType = porter_app.SourceType_DockerRegistry
  286. image = &porter_app.Image{
  287. Repository: inp.ImageRepository,
  288. Tag: inp.ImageTag,
  289. }
  290. }
  291. req := &porter_app.CreateAppRequest{
  292. Name: inp.AppName,
  293. SourceType: sourceType,
  294. GitBranch: inp.GitBranch,
  295. GitRepoName: inp.GitRepoName,
  296. GitRepoID: inp.GitRepoID,
  297. PorterYamlPath: inp.PorterYamlPath,
  298. Image: image,
  299. DeploymentTargetID: inp.DeploymentTargetID,
  300. }
  301. err := c.postRequest(
  302. fmt.Sprintf(
  303. "/projects/%d/clusters/%d/apps/create",
  304. projectID, clusterID,
  305. ),
  306. req,
  307. &types.PorterApp{},
  308. )
  309. return err
  310. }
  311. // CreateSubdomain returns a subdomain for a given service that point to the ingress-nginx service in the cluster
  312. func (c *Client) CreateSubdomain(
  313. ctx context.Context,
  314. projectID uint, clusterID uint,
  315. appName string, serviceName string,
  316. ) (*porter_app.CreateSubdomainResponse, error) {
  317. resp := &porter_app.CreateSubdomainResponse{}
  318. req := &porter_app.CreateSubdomainRequest{
  319. ServiceName: serviceName,
  320. }
  321. err := c.postRequest(
  322. fmt.Sprintf(
  323. "/projects/%d/clusters/%d/apps/%s/subdomain",
  324. projectID, clusterID, appName,
  325. ),
  326. req,
  327. resp,
  328. )
  329. return resp, err
  330. }
  331. // PredeployStatus checks the current status of a predeploy job for an app revision
  332. func (c *Client) PredeployStatus(
  333. ctx context.Context,
  334. projectID uint, clusterID uint,
  335. appName string, appRevisionId string,
  336. ) (*porter_app.PredeployStatusResponse, error) {
  337. resp := &porter_app.PredeployStatusResponse{}
  338. err := c.getRequest(
  339. fmt.Sprintf(
  340. "/projects/%d/clusters/%d/apps/%s/%s/predeploy-status",
  341. projectID, clusterID, appName, appRevisionId,
  342. ),
  343. nil,
  344. resp,
  345. )
  346. if resp.Status == "" {
  347. return nil, fmt.Errorf("no predeploy status found")
  348. }
  349. return resp, err
  350. }
  351. // UpdateRevisionStatus updates the status of an app revision
  352. func (c *Client) UpdateRevisionStatus(
  353. ctx context.Context,
  354. projectID uint, clusterID uint,
  355. appName string, appRevisionId string,
  356. status models.AppRevisionStatus,
  357. ) (*porter_app.UpdateAppRevisionStatusResponse, error) {
  358. resp := &porter_app.UpdateAppRevisionStatusResponse{}
  359. req := &porter_app.UpdateAppRevisionStatusRequest{
  360. Status: status,
  361. }
  362. err := c.postRequest(
  363. fmt.Sprintf(
  364. "/projects/%d/clusters/%d/apps/%s/revisions/%s",
  365. projectID, clusterID, appName, appRevisionId,
  366. ),
  367. req,
  368. resp,
  369. )
  370. return resp, err
  371. }
  372. // GetBuildEnv returns the build environment for a given app proto
  373. func (c *Client) GetBuildEnv(
  374. ctx context.Context,
  375. projectID uint, clusterID uint,
  376. appName string, appRevisionId string,
  377. ) (*porter_app.GetBuildEnvResponse, error) {
  378. resp := &porter_app.GetBuildEnvResponse{}
  379. err := c.getRequest(
  380. fmt.Sprintf(
  381. "/projects/%d/clusters/%d/apps/%s/revisions/%s/build-env",
  382. projectID, clusterID, appName, appRevisionId,
  383. ),
  384. nil,
  385. resp,
  386. )
  387. return resp, err
  388. }
  389. // ReportRevisionStatusInput is the input struct to ReportRevisionStatus
  390. type ReportRevisionStatusInput struct {
  391. ProjectID uint
  392. ClusterID uint
  393. AppName string
  394. AppRevisionID string
  395. PRNumber int
  396. CommitSHA string
  397. }
  398. // ReportRevisionStatus reports the status of an app revision to external services
  399. func (c *Client) ReportRevisionStatus(
  400. ctx context.Context,
  401. inp ReportRevisionStatusInput,
  402. ) (*porter_app.ReportRevisionStatusResponse, error) {
  403. resp := &porter_app.ReportRevisionStatusResponse{}
  404. req := &porter_app.ReportRevisionStatusRequest{
  405. PRNumber: inp.PRNumber,
  406. CommitSHA: inp.CommitSHA,
  407. }
  408. err := c.postRequest(
  409. fmt.Sprintf(
  410. "/projects/%d/clusters/%d/apps/%s/revisions/%s/status",
  411. inp.ProjectID, inp.ClusterID, inp.AppName, inp.AppRevisionID,
  412. ),
  413. req,
  414. resp,
  415. )
  416. return resp, err
  417. }
  418. // CreateOrUpdateAppEnvironment updates the app environment group and creates it if it doesn't exist
  419. func (c *Client) CreateOrUpdateAppEnvironment(
  420. ctx context.Context,
  421. projectID uint, clusterID uint,
  422. appName string,
  423. deploymentTargetID string,
  424. variables map[string]string,
  425. secrets map[string]string,
  426. Base64AppProto string,
  427. ) (*porter_app.UpdateAppEnvironmentResponse, error) {
  428. resp := &porter_app.UpdateAppEnvironmentResponse{}
  429. req := &porter_app.UpdateAppEnvironmentRequest{
  430. DeploymentTargetID: deploymentTargetID,
  431. Variables: variables,
  432. Secrets: secrets,
  433. HardUpdate: false,
  434. Base64AppProto: Base64AppProto,
  435. }
  436. err := c.postRequest(
  437. fmt.Sprintf(
  438. "/projects/%d/clusters/%d/apps/%s/update-environment",
  439. projectID, clusterID, appName,
  440. ),
  441. req,
  442. resp,
  443. )
  444. return resp, err
  445. }
  446. // PorterYamlV2Pods gets all pods for a given deployment target id and app name
  447. func (c *Client) PorterYamlV2Pods(
  448. ctx context.Context,
  449. projectID, clusterID uint,
  450. porterAppName string,
  451. req *types.PorterYamlV2PodsRequest,
  452. ) (*types.GetReleaseAllPodsResponse, error) {
  453. resp := &types.GetReleaseAllPodsResponse{}
  454. err := c.getRequest(
  455. fmt.Sprintf(
  456. "/projects/%d/clusters/%d/apps/%s/pods",
  457. projectID, clusterID,
  458. porterAppName,
  459. ),
  460. req,
  461. resp,
  462. )
  463. return resp, err
  464. }
  465. // UpdateImage updates the image for a porter app (porter yaml v2 only)
  466. func (c *Client) UpdateImage(
  467. ctx context.Context,
  468. projectID, clusterID uint,
  469. appName, deploymentTargetId, tag string,
  470. ) (*porter_app.UpdateImageResponse, error) {
  471. req := &porter_app.UpdateImageRequest{
  472. Tag: tag,
  473. DeploymentTargetId: deploymentTargetId,
  474. }
  475. resp := &porter_app.UpdateImageResponse{}
  476. err := c.postRequest(
  477. fmt.Sprintf(
  478. "/projects/%d/clusters/%d/apps/%s/update-image",
  479. projectID, clusterID, appName,
  480. ),
  481. &req,
  482. resp,
  483. )
  484. return resp, err
  485. }
  486. // ListAppRevisions lists the last ten app revisions for a given app
  487. func (c *Client) ListAppRevisions(
  488. ctx context.Context,
  489. projectID, clusterID uint,
  490. appName string,
  491. deploymentTargetID string,
  492. ) (*porter_app.ListAppRevisionsResponse, error) {
  493. resp := &porter_app.ListAppRevisionsResponse{}
  494. req := &porter_app.ListAppRevisionsRequest{
  495. DeploymentTargetID: deploymentTargetID,
  496. }
  497. err := c.getRequest(
  498. fmt.Sprintf(
  499. "/projects/%d/clusters/%d/apps/%s/revisions",
  500. projectID, clusterID,
  501. appName,
  502. ),
  503. req,
  504. resp,
  505. )
  506. return resp, err
  507. }
  508. // RollbackRevision reverts an app to a previous revision
  509. func (c *Client) RollbackRevision(
  510. ctx context.Context,
  511. projectID, clusterID uint,
  512. appName string,
  513. deploymentTargetID string,
  514. ) (*porter_app.RollbackAppRevisionResponse, error) {
  515. resp := &porter_app.RollbackAppRevisionResponse{}
  516. req := &porter_app.RollbackAppRevisionRequest{
  517. DeploymentTargetID: deploymentTargetID,
  518. }
  519. err := c.postRequest(
  520. fmt.Sprintf(
  521. "/projects/%d/clusters/%d/apps/%s/rollback",
  522. projectID, clusterID,
  523. appName,
  524. ),
  525. req,
  526. resp,
  527. )
  528. return resp, err
  529. }