porter_app.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  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. }
  269. // CreatePorterAppDBEntry creates an entry in the porter app
  270. func (c *Client) CreatePorterAppDBEntry(
  271. ctx context.Context,
  272. projectID uint, clusterID uint,
  273. inp CreatePorterAppDBEntryInput,
  274. ) error {
  275. var sourceType porter_app.SourceType
  276. var image *porter_app.Image
  277. if inp.Local {
  278. sourceType = porter_app.SourceType_Local
  279. }
  280. if inp.GitRepoName != "" {
  281. sourceType = porter_app.SourceType_Github
  282. }
  283. if inp.ImageRepository != "" {
  284. sourceType = porter_app.SourceType_DockerRegistry
  285. image = &porter_app.Image{
  286. Repository: inp.ImageRepository,
  287. Tag: inp.ImageTag,
  288. }
  289. }
  290. req := &porter_app.CreateAppRequest{
  291. Name: inp.AppName,
  292. SourceType: sourceType,
  293. GitBranch: inp.GitBranch,
  294. GitRepoName: inp.GitRepoName,
  295. GitRepoID: inp.GitRepoID,
  296. PorterYamlPath: inp.PorterYamlPath,
  297. Image: image,
  298. }
  299. err := c.postRequest(
  300. fmt.Sprintf(
  301. "/projects/%d/clusters/%d/apps/create",
  302. projectID, clusterID,
  303. ),
  304. req,
  305. &types.PorterApp{},
  306. )
  307. return err
  308. }
  309. // CreateSubdomain returns a subdomain for a given service that point to the ingress-nginx service in the cluster
  310. func (c *Client) CreateSubdomain(
  311. ctx context.Context,
  312. projectID uint, clusterID uint,
  313. appName string, serviceName string,
  314. ) (*porter_app.CreateSubdomainResponse, error) {
  315. resp := &porter_app.CreateSubdomainResponse{}
  316. req := &porter_app.CreateSubdomainRequest{
  317. ServiceName: serviceName,
  318. }
  319. err := c.postRequest(
  320. fmt.Sprintf(
  321. "/projects/%d/clusters/%d/apps/%s/subdomain",
  322. projectID, clusterID, appName,
  323. ),
  324. req,
  325. resp,
  326. )
  327. return resp, err
  328. }
  329. // PredeployStatus checks the current status of a predeploy job for an app revision
  330. func (c *Client) PredeployStatus(
  331. ctx context.Context,
  332. projectID uint, clusterID uint,
  333. appName string, appRevisionId string,
  334. ) (*porter_app.PredeployStatusResponse, error) {
  335. resp := &porter_app.PredeployStatusResponse{}
  336. err := c.getRequest(
  337. fmt.Sprintf(
  338. "/projects/%d/clusters/%d/apps/%s/%s/predeploy-status",
  339. projectID, clusterID, appName, appRevisionId,
  340. ),
  341. nil,
  342. resp,
  343. )
  344. if resp.Status == "" {
  345. return nil, fmt.Errorf("no predeploy status found")
  346. }
  347. return resp, err
  348. }
  349. // UpdateRevisionStatus updates the status of an app revision
  350. func (c *Client) UpdateRevisionStatus(
  351. ctx context.Context,
  352. projectID uint, clusterID uint,
  353. appName string, appRevisionId string,
  354. status models.AppRevisionStatus,
  355. ) (*porter_app.UpdateAppRevisionStatusResponse, error) {
  356. resp := &porter_app.UpdateAppRevisionStatusResponse{}
  357. req := &porter_app.UpdateAppRevisionStatusRequest{
  358. Status: status,
  359. }
  360. err := c.postRequest(
  361. fmt.Sprintf(
  362. "/projects/%d/clusters/%d/apps/%s/revisions/%s",
  363. projectID, clusterID, appName, appRevisionId,
  364. ),
  365. req,
  366. resp,
  367. )
  368. return resp, err
  369. }
  370. // GetBuildEnv returns the build environment for a given app proto
  371. func (c *Client) GetBuildEnv(
  372. ctx context.Context,
  373. projectID uint, clusterID uint,
  374. appName string, appRevisionId string,
  375. ) (*porter_app.GetBuildEnvResponse, error) {
  376. resp := &porter_app.GetBuildEnvResponse{}
  377. err := c.getRequest(
  378. fmt.Sprintf(
  379. "/projects/%d/clusters/%d/apps/%s/revisions/%s/build-env",
  380. projectID, clusterID, appName, appRevisionId,
  381. ),
  382. nil,
  383. resp,
  384. )
  385. return resp, err
  386. }
  387. // ReportRevisionStatusInput is the input struct to ReportRevisionStatus
  388. type ReportRevisionStatusInput struct {
  389. ProjectID uint
  390. ClusterID uint
  391. AppName string
  392. AppRevisionID string
  393. PRNumber int
  394. CommitSHA string
  395. }
  396. // ReportRevisionStatus reports the status of an app revision to external services
  397. func (c *Client) ReportRevisionStatus(
  398. ctx context.Context,
  399. inp ReportRevisionStatusInput,
  400. ) (*porter_app.ReportRevisionStatusResponse, error) {
  401. resp := &porter_app.ReportRevisionStatusResponse{}
  402. req := &porter_app.ReportRevisionStatusRequest{
  403. PRNumber: inp.PRNumber,
  404. CommitSHA: inp.CommitSHA,
  405. }
  406. err := c.postRequest(
  407. fmt.Sprintf(
  408. "/projects/%d/clusters/%d/apps/%s/revisions/%s/status",
  409. inp.ProjectID, inp.ClusterID, inp.AppName, inp.AppRevisionID,
  410. ),
  411. req,
  412. resp,
  413. )
  414. return resp, err
  415. }
  416. // CreateOrUpdateAppEnvironment updates the app environment group and creates it if it doesn't exist
  417. func (c *Client) CreateOrUpdateAppEnvironment(
  418. ctx context.Context,
  419. projectID uint, clusterID uint,
  420. appName string,
  421. deploymentTargetID string,
  422. variables map[string]string,
  423. secrets map[string]string,
  424. Base64AppProto string,
  425. ) (*porter_app.UpdateAppEnvironmentResponse, error) {
  426. resp := &porter_app.UpdateAppEnvironmentResponse{}
  427. req := &porter_app.UpdateAppEnvironmentRequest{
  428. DeploymentTargetID: deploymentTargetID,
  429. Variables: variables,
  430. Secrets: secrets,
  431. HardUpdate: false,
  432. Base64AppProto: Base64AppProto,
  433. }
  434. err := c.postRequest(
  435. fmt.Sprintf(
  436. "/projects/%d/clusters/%d/apps/%s/update-environment",
  437. projectID, clusterID, appName,
  438. ),
  439. req,
  440. resp,
  441. )
  442. return resp, err
  443. }
  444. // PorterYamlV2Pods gets all pods for a given deployment target id and app name
  445. func (c *Client) PorterYamlV2Pods(
  446. ctx context.Context,
  447. projectID, clusterID uint,
  448. porterAppName string,
  449. req *types.PorterYamlV2PodsRequest,
  450. ) (*types.GetReleaseAllPodsResponse, error) {
  451. resp := &types.GetReleaseAllPodsResponse{}
  452. err := c.getRequest(
  453. fmt.Sprintf(
  454. "/projects/%d/clusters/%d/apps/%s/pods",
  455. projectID, clusterID,
  456. porterAppName,
  457. ),
  458. req,
  459. resp,
  460. )
  461. return resp, err
  462. }
  463. // UpdateImage updates the image for a porter app (porter yaml v2 only)
  464. func (c *Client) UpdateImage(
  465. ctx context.Context,
  466. projectID, clusterID uint,
  467. appName, deploymentTargetId, tag string,
  468. ) (*porter_app.UpdateImageResponse, error) {
  469. req := &porter_app.UpdateImageRequest{
  470. Tag: tag,
  471. DeploymentTargetId: deploymentTargetId,
  472. }
  473. resp := &porter_app.UpdateImageResponse{}
  474. err := c.postRequest(
  475. fmt.Sprintf(
  476. "/projects/%d/clusters/%d/apps/%s/update-image",
  477. projectID, clusterID, appName,
  478. ),
  479. &req,
  480. resp,
  481. )
  482. return resp, err
  483. }
  484. // ListAppRevisions lists the last ten app revisions for a given app
  485. func (c *Client) ListAppRevisions(
  486. ctx context.Context,
  487. projectID, clusterID uint,
  488. appName string,
  489. deploymentTargetID string,
  490. ) (*porter_app.ListAppRevisionsResponse, error) {
  491. resp := &porter_app.ListAppRevisionsResponse{}
  492. req := &porter_app.ListAppRevisionsRequest{
  493. DeploymentTargetID: deploymentTargetID,
  494. }
  495. err := c.getRequest(
  496. fmt.Sprintf(
  497. "/projects/%d/clusters/%d/apps/%s/revisions",
  498. projectID, clusterID,
  499. appName,
  500. ),
  501. req,
  502. resp,
  503. )
  504. return resp, err
  505. }
  506. // RollbackRevision reverts an app to a previous revision
  507. func (c *Client) RollbackRevision(
  508. ctx context.Context,
  509. projectID, clusterID uint,
  510. appName string,
  511. deploymentTargetID string,
  512. ) (*porter_app.RollbackAppRevisionResponse, error) {
  513. resp := &porter_app.RollbackAppRevisionResponse{}
  514. req := &porter_app.RollbackAppRevisionRequest{
  515. DeploymentTargetID: deploymentTargetID,
  516. }
  517. err := c.postRequest(
  518. fmt.Sprintf(
  519. "/projects/%d/clusters/%d/apps/%s/rollback",
  520. projectID, clusterID,
  521. appName,
  522. ),
  523. req,
  524. resp,
  525. )
  526. return resp, err
  527. }