2
0

porter_app.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. package client
  2. import (
  3. "context"
  4. "encoding/base64"
  5. "encoding/json"
  6. "fmt"
  7. "time"
  8. "github.com/gorilla/websocket"
  9. "github.com/porter-dev/porter/api/server/handlers/porter_app"
  10. "github.com/porter-dev/porter/internal/models"
  11. appInternal "github.com/porter-dev/porter/internal/porter_app"
  12. v2 "github.com/porter-dev/porter/internal/porter_app/v2"
  13. "github.com/porter-dev/porter/api/types"
  14. )
  15. func (c *Client) NewGetPorterApp(
  16. ctx context.Context,
  17. projectID, clusterID uint,
  18. appName string,
  19. ) (*types.PorterApp, error) {
  20. resp := &types.PorterApp{}
  21. err := c.getRequest(
  22. fmt.Sprintf(
  23. "/projects/%d/clusters/%d/applications/%s",
  24. projectID, clusterID, appName,
  25. ),
  26. nil,
  27. resp,
  28. )
  29. return resp, err
  30. }
  31. func (c *Client) NewCreatePorterApp(
  32. ctx context.Context,
  33. projectID, clusterID uint,
  34. appName string,
  35. req *types.CreatePorterAppRequest,
  36. ) (*types.PorterApp, error) {
  37. resp := &types.PorterApp{}
  38. err := c.postRequest(
  39. fmt.Sprintf(
  40. "/projects/%d/clusters/%d/applications/%s",
  41. projectID, clusterID, appName,
  42. ),
  43. req,
  44. resp,
  45. )
  46. return resp, err
  47. }
  48. // 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
  49. func (c *Client) NewCreateOrUpdatePorterAppEvent(
  50. ctx context.Context,
  51. projectID, clusterID uint,
  52. appName string,
  53. req *types.CreateOrUpdatePorterAppEventRequest,
  54. ) (types.PorterAppEvent, error) {
  55. resp := &types.PorterAppEvent{}
  56. err := c.postRequest(
  57. fmt.Sprintf(
  58. "/projects/%d/clusters/%d/applications/%s/events",
  59. projectID, clusterID, appName,
  60. ),
  61. req,
  62. resp,
  63. )
  64. return *resp, err
  65. }
  66. // TODO: remove these functions once they are no longer called (check telemetry)
  67. func (c *Client) GetPorterApp(
  68. ctx context.Context,
  69. projectID, clusterID uint,
  70. stackName string,
  71. ) (*types.PorterApp, error) {
  72. resp := &types.PorterApp{}
  73. err := c.getRequest(
  74. fmt.Sprintf(
  75. "/projects/%d/clusters/%d/stacks/%s",
  76. projectID, clusterID, stackName,
  77. ),
  78. nil,
  79. resp,
  80. )
  81. return resp, err
  82. }
  83. func (c *Client) CreatePorterApp(
  84. ctx context.Context,
  85. projectID, clusterID uint,
  86. name string,
  87. req *types.CreatePorterAppRequest,
  88. ) (*types.PorterApp, error) {
  89. resp := &types.PorterApp{}
  90. err := c.postRequest(
  91. fmt.Sprintf(
  92. "/projects/%d/clusters/%d/stacks/%s",
  93. projectID, clusterID, name,
  94. ),
  95. req,
  96. resp,
  97. )
  98. return resp, err
  99. }
  100. // 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
  101. func (c *Client) CreateOrUpdatePorterAppEvent(
  102. ctx context.Context,
  103. projectID, clusterID uint,
  104. name string,
  105. req *types.CreateOrUpdatePorterAppEventRequest,
  106. ) (types.PorterAppEvent, error) {
  107. resp := &types.PorterAppEvent{}
  108. err := c.postRequest(
  109. fmt.Sprintf(
  110. "/projects/%d/clusters/%d/stacks/%s/events",
  111. projectID, clusterID, name,
  112. ),
  113. req,
  114. resp,
  115. )
  116. return *resp, err
  117. }
  118. // ListEnvGroups (List all Env Groups for a given cluster)
  119. func (c *Client) ListEnvGroups(
  120. ctx context.Context,
  121. projectID, clusterID uint,
  122. ) (types.ListEnvironmentGroupsResponse, error) {
  123. resp := &types.ListEnvironmentGroupsResponse{}
  124. err := c.getRequest(
  125. fmt.Sprintf(
  126. "/projects/%d/clusters/%d/environment-groups",
  127. projectID, clusterID,
  128. ),
  129. nil,
  130. resp,
  131. )
  132. return *resp, err
  133. }
  134. // ParseYAML takes in a base64 encoded porter yaml and returns an app proto
  135. func (c *Client) ParseYAML(
  136. ctx context.Context,
  137. projectID, clusterID uint,
  138. b64Yaml string,
  139. appName string,
  140. patchOperations []v2.PatchOperation,
  141. ) (*porter_app.ParsePorterYAMLToProtoResponse, error) {
  142. resp := &porter_app.ParsePorterYAMLToProtoResponse{}
  143. req := &porter_app.ParsePorterYAMLToProtoRequest{
  144. B64Yaml: b64Yaml,
  145. AppName: appName,
  146. PatchOperations: patchOperations,
  147. }
  148. err := c.postRequest(
  149. fmt.Sprintf(
  150. "/projects/%d/clusters/%d/apps/parse",
  151. projectID, clusterID,
  152. ),
  153. req,
  154. resp,
  155. )
  156. return resp, err
  157. }
  158. // GetAppManifests returns the manifests for a given app based on the latest successful app revision
  159. func (c *Client) GetAppManifests(
  160. ctx context.Context,
  161. projectID, clusterID uint,
  162. appName string,
  163. ) (*porter_app.AppManifestsResponse, error) {
  164. resp := &porter_app.AppManifestsResponse{}
  165. err := c.getRequest(
  166. fmt.Sprintf(
  167. "/projects/%d/clusters/%d/apps/%s/manifests",
  168. projectID, clusterID, appName,
  169. ),
  170. nil,
  171. resp,
  172. )
  173. return resp, err
  174. }
  175. // UpdateAppInput is the input struct to UpdateApp
  176. type UpdateAppInput struct {
  177. ProjectID uint
  178. ClusterID uint
  179. Name string
  180. ImageTagOverride string
  181. GitSource porter_app.GitSource
  182. DeploymentTargetId string
  183. DeploymentTargetName string
  184. CommitSHA string
  185. AppRevisionID string
  186. Base64AppProto string
  187. Base64PorterYAML string
  188. IsEnvOverride bool
  189. WithPredeploy bool
  190. Exact bool
  191. Variables map[string]string
  192. Secrets map[string]string
  193. Deletions porter_app.Deletions
  194. PatchOperations []v2.PatchOperation
  195. }
  196. // UpdateApp updates a porter app
  197. func (c *Client) UpdateApp(
  198. ctx context.Context,
  199. inp UpdateAppInput,
  200. ) (*porter_app.UpdateAppResponse, error) {
  201. resp := &porter_app.UpdateAppResponse{}
  202. req := &porter_app.UpdateAppRequest{
  203. Name: inp.Name,
  204. GitSource: inp.GitSource,
  205. DeploymentTargetId: inp.DeploymentTargetId,
  206. DeploymentTargetName: inp.DeploymentTargetName,
  207. CommitSHA: inp.CommitSHA,
  208. ImageTagOverride: inp.ImageTagOverride,
  209. AppRevisionID: inp.AppRevisionID,
  210. Base64AppProto: inp.Base64AppProto,
  211. Base64PorterYAML: inp.Base64PorterYAML,
  212. IsEnvOverride: inp.IsEnvOverride,
  213. WithPredeploy: inp.WithPredeploy,
  214. Exact: inp.Exact,
  215. Variables: inp.Variables,
  216. Secrets: inp.Secrets,
  217. Deletions: inp.Deletions,
  218. PatchOperations: inp.PatchOperations,
  219. }
  220. err := c.postRequest(
  221. fmt.Sprintf(
  222. "/projects/%d/clusters/%d/apps/update",
  223. inp.ProjectID, inp.ClusterID,
  224. ),
  225. req,
  226. resp,
  227. )
  228. return resp, err
  229. }
  230. // AppLogsInput is the input struct to AppLogs and AppLogsStream
  231. type AppLogsInput struct {
  232. ProjectID uint
  233. ClusterID uint
  234. AppName string
  235. ServiceName string
  236. DeploymentTargetName string
  237. StartRange time.Time
  238. }
  239. // AppLogs gets logs for an app
  240. func (c *Client) AppLogs(
  241. ctx context.Context,
  242. inp AppLogsInput,
  243. ) (*porter_app.AppLogsResponse, error) {
  244. resp := &porter_app.AppLogsResponse{}
  245. req := &porter_app.AppLogsRequest{
  246. ServiceName: inp.ServiceName,
  247. DeploymentTargetName: inp.DeploymentTargetName,
  248. StartRange: inp.StartRange,
  249. }
  250. err := c.getRequest(
  251. fmt.Sprintf(
  252. "/projects/%d/clusters/%d/apps/%s/logs",
  253. inp.ProjectID, inp.ClusterID, inp.AppName,
  254. ),
  255. req,
  256. resp,
  257. )
  258. return resp, err
  259. }
  260. // AppLogsStream streams logs for an app
  261. func (c *Client) AppLogsStream(
  262. ctx context.Context,
  263. inp AppLogsInput,
  264. ) (*websocket.Conn, error) {
  265. req := &porter_app.AppLogsRequest{
  266. ServiceName: inp.ServiceName,
  267. DeploymentTargetName: inp.DeploymentTargetName,
  268. }
  269. conn, err := c.websocketDial(
  270. fmt.Sprintf(
  271. "/projects/%d/clusters/%d/apps/%s/logs/loki",
  272. inp.ProjectID, inp.ClusterID, inp.AppName,
  273. ),
  274. req,
  275. )
  276. if err != nil {
  277. return conn, err
  278. }
  279. return conn, nil
  280. }
  281. // DefaultDeploymentTarget returns the default deployment target for a given project and cluster
  282. func (c *Client) DefaultDeploymentTarget(
  283. ctx context.Context,
  284. projectID, clusterID uint,
  285. ) (*porter_app.DefaultDeploymentTargetResponse, error) {
  286. resp := &porter_app.DefaultDeploymentTargetResponse{}
  287. req := &porter_app.DefaultDeploymentTargetRequest{}
  288. err := c.getRequest(
  289. fmt.Sprintf(
  290. "/projects/%d/clusters/%d/default-deployment-target",
  291. projectID, clusterID,
  292. ),
  293. req,
  294. resp,
  295. )
  296. return resp, err
  297. }
  298. // CurrentAppRevisionInput is the input struct to CurrentAppRevision
  299. type CurrentAppRevisionInput struct {
  300. ProjectID uint
  301. ClusterID uint
  302. AppName string
  303. // DeploymentTargetName is the name of the deployment target to get the current app revision for. One of this or DeploymentTargetID must be set.
  304. DeploymentTargetName string
  305. // DeploymentTargetID is the id of the deployment target to get the current app revision for. One of this or DeploymentTargetName must be set.
  306. DeploymentTargetID string
  307. }
  308. // CurrentAppRevision returns the currently deployed app revision for a given project, app name and deployment target
  309. func (c *Client) CurrentAppRevision(
  310. ctx context.Context,
  311. input CurrentAppRevisionInput,
  312. ) (*porter_app.LatestAppRevisionResponse, error) {
  313. resp := &porter_app.LatestAppRevisionResponse{}
  314. req := &porter_app.LatestAppRevisionRequest{
  315. DeploymentTargetName: input.DeploymentTargetName,
  316. DeploymentTargetID: input.DeploymentTargetID,
  317. }
  318. err := c.getRequest(
  319. fmt.Sprintf(
  320. "/projects/%d/clusters/%d/apps/%s/latest",
  321. input.ProjectID, input.ClusterID, input.AppName,
  322. ),
  323. req,
  324. resp,
  325. )
  326. return resp, err
  327. }
  328. // CreatePorterAppDBEntryInput is the input struct to CreatePorterAppDBEntry
  329. type CreatePorterAppDBEntryInput struct {
  330. AppName string
  331. GitRepoName string
  332. GitRepoID uint
  333. GitBranch string
  334. ImageRepository string
  335. PorterYamlPath string
  336. ImageTag string
  337. Local bool
  338. DeploymentTargetID string
  339. }
  340. // CreatePorterAppDBEntry creates an entry in the porter app
  341. func (c *Client) CreatePorterAppDBEntry(
  342. ctx context.Context,
  343. projectID uint, clusterID uint,
  344. inp CreatePorterAppDBEntryInput,
  345. ) error {
  346. var sourceType appInternal.SourceType
  347. var image *appInternal.Image
  348. if inp.Local {
  349. sourceType = appInternal.SourceType_Local
  350. }
  351. if inp.GitRepoName != "" {
  352. sourceType = appInternal.SourceType_Github
  353. }
  354. if inp.ImageRepository != "" {
  355. sourceType = appInternal.SourceType_DockerRegistry
  356. image = &appInternal.Image{
  357. Repository: inp.ImageRepository,
  358. Tag: inp.ImageTag,
  359. }
  360. }
  361. req := &porter_app.CreateAppRequest{
  362. Name: inp.AppName,
  363. SourceType: sourceType,
  364. GitSource: porter_app.GitSource{
  365. GitBranch: inp.GitBranch,
  366. GitRepoName: inp.GitRepoName,
  367. GitRepoID: inp.GitRepoID,
  368. },
  369. Image: image,
  370. PorterYamlPath: inp.PorterYamlPath,
  371. DeploymentTargetID: inp.DeploymentTargetID,
  372. }
  373. err := c.postRequest(
  374. fmt.Sprintf(
  375. "/projects/%d/clusters/%d/apps/create",
  376. projectID, clusterID,
  377. ),
  378. req,
  379. &types.PorterApp{},
  380. )
  381. return err
  382. }
  383. // CreateSubdomain returns a subdomain for a given service that point to the ingress-nginx service in the cluster
  384. func (c *Client) CreateSubdomain(
  385. ctx context.Context,
  386. projectID uint, clusterID uint,
  387. appName string, serviceName string,
  388. ) (*porter_app.CreateSubdomainResponse, error) {
  389. resp := &porter_app.CreateSubdomainResponse{}
  390. req := &porter_app.CreateSubdomainRequest{
  391. ServiceName: serviceName,
  392. }
  393. err := c.postRequest(
  394. fmt.Sprintf(
  395. "/projects/%d/clusters/%d/apps/%s/subdomain",
  396. projectID, clusterID, appName,
  397. ),
  398. req,
  399. resp,
  400. )
  401. return resp, err
  402. }
  403. // PredeployStatus checks the current status of a predeploy job for an app revision
  404. func (c *Client) PredeployStatus(
  405. ctx context.Context,
  406. projectID uint, clusterID uint,
  407. appName string, appRevisionId string,
  408. ) (*porter_app.PredeployStatusResponse, error) {
  409. resp := &porter_app.PredeployStatusResponse{}
  410. err := c.getRequest(
  411. fmt.Sprintf(
  412. "/projects/%d/clusters/%d/apps/%s/%s/predeploy-status",
  413. projectID, clusterID, appName, appRevisionId,
  414. ),
  415. nil,
  416. resp,
  417. )
  418. if resp.Status == "" {
  419. return nil, fmt.Errorf("no predeploy status found")
  420. }
  421. return resp, err
  422. }
  423. // GetRevision returns an app revision
  424. func (c *Client) GetRevision(
  425. ctx context.Context,
  426. projectID uint, clusterID uint,
  427. appName string, appRevisionId string,
  428. ) (*porter_app.GetAppRevisionResponse, error) {
  429. resp := &porter_app.GetAppRevisionResponse{}
  430. err := c.getRequest(
  431. fmt.Sprintf(
  432. "/projects/%d/clusters/%d/apps/%s/revisions/%s",
  433. projectID, clusterID, appName, appRevisionId,
  434. ),
  435. nil,
  436. resp,
  437. )
  438. return resp, err
  439. }
  440. // GetRevisionStatus returns the status of an app revision
  441. func (c *Client) GetRevisionStatus(
  442. ctx context.Context,
  443. projectID uint, clusterID uint,
  444. appName string, appRevisionId string,
  445. ) (*porter_app.GetAppRevisionStatusResponse, error) {
  446. resp := &porter_app.GetAppRevisionStatusResponse{}
  447. err := c.getRequest(
  448. fmt.Sprintf(
  449. "/projects/%d/clusters/%d/apps/%s/revisions/%s/status",
  450. projectID, clusterID, appName, appRevisionId,
  451. ),
  452. nil,
  453. resp,
  454. )
  455. return resp, err
  456. }
  457. // UpdateRevisionStatus updates the status of an app revision
  458. func (c *Client) UpdateRevisionStatus(
  459. ctx context.Context,
  460. projectID uint, clusterID uint,
  461. appName string, appRevisionId string,
  462. status models.AppRevisionStatus,
  463. ) (*porter_app.UpdateAppRevisionStatusResponse, error) {
  464. resp := &porter_app.UpdateAppRevisionStatusResponse{}
  465. req := &porter_app.UpdateAppRevisionStatusRequest{
  466. Status: status,
  467. }
  468. err := c.postRequest(
  469. fmt.Sprintf(
  470. "/projects/%d/clusters/%d/apps/%s/revisions/%s",
  471. projectID, clusterID, appName, appRevisionId,
  472. ),
  473. req,
  474. resp,
  475. )
  476. return resp, err
  477. }
  478. // GetBuildEnv returns the build environment for a given app proto
  479. func (c *Client) GetBuildEnv(
  480. ctx context.Context,
  481. projectID uint, clusterID uint,
  482. appName string, appRevisionId string,
  483. ) (*porter_app.GetBuildEnvResponse, error) {
  484. resp := &porter_app.GetBuildEnvResponse{}
  485. err := c.getRequest(
  486. fmt.Sprintf(
  487. "/projects/%d/clusters/%d/apps/%s/revisions/%s/build-env",
  488. projectID, clusterID, appName, appRevisionId,
  489. ),
  490. nil,
  491. resp,
  492. )
  493. return resp, err
  494. }
  495. // GetAppEnvVariables returns all env variables for a given app
  496. func (c *Client) GetAppEnvVariables(
  497. ctx context.Context,
  498. projectID uint, clusterID uint,
  499. appName string,
  500. deploymentTargetName string,
  501. ) (*porter_app.AppEnvVariablesResponse, error) {
  502. resp := &porter_app.AppEnvVariablesResponse{}
  503. req := &porter_app.AppEnvVariablesRequest{
  504. DeploymentTargetName: deploymentTargetName,
  505. }
  506. err := c.getRequest(
  507. fmt.Sprintf(
  508. "/projects/%d/clusters/%d/apps/%s/env-variables",
  509. projectID, clusterID, appName,
  510. ),
  511. req,
  512. resp,
  513. )
  514. return resp, err
  515. }
  516. // GetBuildFromRevisionInput is the input struct to GetBuildFromRevision
  517. type GetBuildFromRevisionInput struct {
  518. ProjectID uint
  519. ClusterID uint
  520. AppName string
  521. AppRevisionID string
  522. PatchOperations []v2.PatchOperation
  523. }
  524. // GetBuildFromRevision returns the build environment for a given app proto
  525. func (c *Client) GetBuildFromRevision(
  526. ctx context.Context,
  527. inp GetBuildFromRevisionInput,
  528. ) (*porter_app.GetBuildFromRevisionResponse, error) {
  529. by, err := json.Marshal(inp.PatchOperations)
  530. if err != nil {
  531. return nil, fmt.Errorf("error marshalling patch operations: %w", err)
  532. }
  533. encoded := base64.StdEncoding.EncodeToString(by)
  534. req := &porter_app.GetBuildFromRevisionRequest{
  535. B64PatchOperations: encoded,
  536. }
  537. resp := &porter_app.GetBuildFromRevisionResponse{}
  538. err = c.getRequest(
  539. fmt.Sprintf(
  540. "/projects/%d/clusters/%d/apps/%s/revisions/%s/build",
  541. inp.ProjectID, inp.ClusterID, inp.AppName, inp.AppRevisionID,
  542. ),
  543. req,
  544. resp,
  545. )
  546. return resp, err
  547. }
  548. // ReportRevisionStatusInput is the input struct to ReportRevisionStatus
  549. type ReportRevisionStatusInput struct {
  550. ProjectID uint
  551. ClusterID uint
  552. AppName string
  553. AppRevisionID string
  554. PRNumber int
  555. CommitSHA string
  556. }
  557. // ReportRevisionStatus reports the status of an app revision to external services
  558. func (c *Client) ReportRevisionStatus(
  559. ctx context.Context,
  560. inp ReportRevisionStatusInput,
  561. ) (*porter_app.ReportRevisionStatusResponse, error) {
  562. resp := &porter_app.ReportRevisionStatusResponse{}
  563. req := &porter_app.ReportRevisionStatusRequest{
  564. PRNumber: inp.PRNumber,
  565. CommitSHA: inp.CommitSHA,
  566. }
  567. err := c.postRequest(
  568. fmt.Sprintf(
  569. "/projects/%d/clusters/%d/apps/%s/revisions/%s/status",
  570. inp.ProjectID, inp.ClusterID, inp.AppName, inp.AppRevisionID,
  571. ),
  572. req,
  573. resp,
  574. )
  575. return resp, err
  576. }
  577. // PorterYamlV2Pods gets all pods for a given deployment target id and app name
  578. func (c *Client) PorterYamlV2Pods(
  579. ctx context.Context,
  580. projectID, clusterID uint,
  581. porterAppName string,
  582. deploymentTargetName string,
  583. ) (*types.GetReleaseAllPodsResponse, error) {
  584. req := &porter_app.PodStatusRequest{
  585. DeploymentTargetName: deploymentTargetName,
  586. }
  587. resp := &types.GetReleaseAllPodsResponse{}
  588. err := c.getRequest(
  589. fmt.Sprintf(
  590. "/projects/%d/clusters/%d/apps/%s/pods",
  591. projectID, clusterID,
  592. porterAppName,
  593. ),
  594. req,
  595. resp,
  596. )
  597. return resp, err
  598. }
  599. // UpdateImage updates the image for a porter app (porter yaml v2 only)
  600. func (c *Client) UpdateImage(
  601. ctx context.Context,
  602. projectID, clusterID uint,
  603. appName, deploymentTargetName, tag string,
  604. ) (*porter_app.UpdateImageResponse, error) {
  605. req := &porter_app.UpdateImageRequest{
  606. Tag: tag,
  607. DeploymentTargetName: deploymentTargetName,
  608. }
  609. resp := &porter_app.UpdateImageResponse{}
  610. err := c.postRequest(
  611. fmt.Sprintf(
  612. "/projects/%d/clusters/%d/apps/%s/update-image",
  613. projectID, clusterID, appName,
  614. ),
  615. &req,
  616. resp,
  617. )
  618. return resp, err
  619. }
  620. // ListAppRevisions lists the last ten app revisions for a given app
  621. func (c *Client) ListAppRevisions(
  622. ctx context.Context,
  623. projectID, clusterID uint,
  624. appName string,
  625. deploymentTargetID string,
  626. ) (*porter_app.ListAppRevisionsResponse, error) {
  627. resp := &porter_app.ListAppRevisionsResponse{}
  628. req := &porter_app.ListAppRevisionsRequest{
  629. DeploymentTargetID: deploymentTargetID,
  630. }
  631. err := c.getRequest(
  632. fmt.Sprintf(
  633. "/projects/%d/clusters/%d/apps/%s/revisions",
  634. projectID, clusterID,
  635. appName,
  636. ),
  637. req,
  638. resp,
  639. )
  640. return resp, err
  641. }
  642. // RollbackRevision reverts an app to a previous revision
  643. func (c *Client) RollbackRevision(
  644. ctx context.Context,
  645. projectID, clusterID uint,
  646. appName string,
  647. deploymentTargetName string,
  648. ) (*porter_app.RollbackAppRevisionResponse, error) {
  649. resp := &porter_app.RollbackAppRevisionResponse{}
  650. req := &porter_app.RollbackAppRevisionRequest{
  651. DeploymentTargetName: deploymentTargetName,
  652. }
  653. err := c.postRequest(
  654. fmt.Sprintf(
  655. "/projects/%d/clusters/%d/apps/%s/rollback",
  656. projectID, clusterID,
  657. appName,
  658. ),
  659. req,
  660. resp,
  661. )
  662. return resp, err
  663. }
  664. // RunAppJob runs a job for an app
  665. func (c *Client) RunAppJob(
  666. ctx context.Context,
  667. projectID, clusterID uint,
  668. appName string, jobName string,
  669. deploymentTargetName string,
  670. ) (*porter_app.RunAppJobResponse, error) {
  671. resp := &porter_app.RunAppJobResponse{}
  672. req := &porter_app.RunAppJobRequest{
  673. ServiceName: jobName,
  674. DeploymentTargetName: deploymentTargetName,
  675. }
  676. err := c.postRequest(
  677. fmt.Sprintf(
  678. "/projects/%d/clusters/%d/apps/%s/run",
  679. projectID, clusterID,
  680. appName,
  681. ),
  682. req,
  683. resp,
  684. )
  685. return resp, err
  686. }
  687. // CancelAppJobInput contains all the information necessary to cancel a job
  688. type CancelAppJobInput struct {
  689. ProjectID uint
  690. ClusterID uint
  691. AppName string
  692. JobName string
  693. DeploymentTargetName string
  694. }
  695. // CancelAppJobRun cancels a in progress job run
  696. func (c *Client) CancelAppJobRun(
  697. ctx context.Context,
  698. inp CancelAppJobInput,
  699. ) (*porter_app.CancelJobRunResponse, error) {
  700. resp := &porter_app.CancelJobRunResponse{}
  701. req := &porter_app.CancelJobRunRequest{
  702. DeploymentTargetName: inp.DeploymentTargetName,
  703. }
  704. err := c.postRequest(
  705. fmt.Sprintf(
  706. "/projects/%d/clusters/%d/apps/%s/jobs/%s/cancel",
  707. inp.ProjectID, inp.ClusterID,
  708. inp.AppName, inp.JobName,
  709. ),
  710. req,
  711. resp,
  712. )
  713. return resp, err
  714. }
  715. // RunAppJobStatusInput contains all the information necessary to check the status of a job
  716. type RunAppJobStatusInput struct {
  717. // AppName is the name of the app associated with the job
  718. AppName string
  719. // Cluster is the id of the cluster against which to retrieve a helm agent for
  720. ClusterID uint
  721. // DeploymentTargetName is the id of the deployment target the job was run against
  722. DeploymentTargetName string
  723. // ServiceName is the name of the app service that was triggered
  724. ServiceName string
  725. // JobRunID is the UID returned from the /apps/{porter_app_name}/run endpoint
  726. JobRunID string
  727. // ProjectID is the project in which the cluster exists
  728. ProjectID uint
  729. }
  730. // RunAppJobStatus gets the status for a job app run
  731. func (c *Client) RunAppJobStatus(
  732. ctx context.Context,
  733. input RunAppJobStatusInput,
  734. ) (*porter_app.AppJobRunStatusResponse, error) {
  735. resp := &porter_app.AppJobRunStatusResponse{}
  736. req := &porter_app.AppJobRunStatusRequest{
  737. DeploymentTargetName: input.DeploymentTargetName,
  738. JobRunID: input.JobRunID,
  739. ServiceName: input.ServiceName,
  740. }
  741. err := c.getRequest(
  742. fmt.Sprintf(
  743. "/projects/%d/clusters/%d/apps/%s/run-status",
  744. input.ProjectID, input.ClusterID,
  745. input.AppName,
  746. ),
  747. req,
  748. resp,
  749. )
  750. return resp, err
  751. }