porter_app.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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. req := &porter_app.CreateAppRequest{
  273. Name: inp.AppName,
  274. SourceType: sourceType,
  275. GitBranch: inp.GitBranch,
  276. GitRepoName: inp.GitRepoName,
  277. GitRepoID: inp.GitRepoID,
  278. PorterYamlPath: inp.PorterYamlPath,
  279. Image: image,
  280. }
  281. err := c.postRequest(
  282. fmt.Sprintf(
  283. "/projects/%d/clusters/%d/apps/create",
  284. projectID, clusterID,
  285. ),
  286. req,
  287. &types.PorterApp{},
  288. )
  289. return err
  290. }
  291. // CreateSubdomain returns a subdomain for a given service that point to the ingress-nginx service in the cluster
  292. func (c *Client) CreateSubdomain(
  293. ctx context.Context,
  294. projectID uint, clusterID uint,
  295. appName string, serviceName string,
  296. ) (*porter_app.CreateSubdomainResponse, error) {
  297. resp := &porter_app.CreateSubdomainResponse{}
  298. req := &porter_app.CreateSubdomainRequest{
  299. ServiceName: serviceName,
  300. }
  301. err := c.postRequest(
  302. fmt.Sprintf(
  303. "/projects/%d/clusters/%d/apps/%s/subdomain",
  304. projectID, clusterID, appName,
  305. ),
  306. req,
  307. resp,
  308. )
  309. return resp, err
  310. }
  311. // PredeployStatus checks the current status of a predeploy job for an app revision
  312. func (c *Client) PredeployStatus(
  313. ctx context.Context,
  314. projectID uint, clusterID uint,
  315. appName string, appRevisionId string,
  316. ) (*porter_app.PredeployStatusResponse, error) {
  317. resp := &porter_app.PredeployStatusResponse{}
  318. err := c.getRequest(
  319. fmt.Sprintf(
  320. "/projects/%d/clusters/%d/apps/%s/%s/predeploy-status",
  321. projectID, clusterID, appName, appRevisionId,
  322. ),
  323. nil,
  324. resp,
  325. )
  326. if resp.Status == "" {
  327. return nil, fmt.Errorf("no predeploy status found")
  328. }
  329. return resp, err
  330. }
  331. // UpdateRevisionStatus updates the status of an app revision
  332. func (c *Client) UpdateRevisionStatus(
  333. ctx context.Context,
  334. projectID uint, clusterID uint,
  335. appName string, appRevisionId string,
  336. status models.AppRevisionStatus,
  337. ) (*porter_app.UpdateAppRevisionStatusResponse, error) {
  338. resp := &porter_app.UpdateAppRevisionStatusResponse{}
  339. req := &porter_app.UpdateAppRevisionStatusRequest{
  340. Status: status,
  341. }
  342. err := c.postRequest(
  343. fmt.Sprintf(
  344. "/projects/%d/clusters/%d/apps/%s/revisions/%s",
  345. projectID, clusterID, appName, appRevisionId,
  346. ),
  347. req,
  348. resp,
  349. )
  350. return resp, err
  351. }
  352. // GetBuildEnv returns the build environment for a given app proto
  353. func (c *Client) GetBuildEnv(
  354. ctx context.Context,
  355. projectID uint, clusterID uint,
  356. appName string, appRevisionId string,
  357. ) (*porter_app.GetBuildEnvResponse, error) {
  358. resp := &porter_app.GetBuildEnvResponse{}
  359. err := c.getRequest(
  360. fmt.Sprintf(
  361. "/projects/%d/clusters/%d/apps/%s/revisions/%s/build-env",
  362. projectID, clusterID, appName, appRevisionId,
  363. ),
  364. nil,
  365. resp,
  366. )
  367. return resp, err
  368. }
  369. // CreateOrUpdateAppEnvironment updates the app environment group and creates it if it doesn't exist
  370. func (c *Client) CreateOrUpdateAppEnvironment(
  371. ctx context.Context,
  372. projectID uint, clusterID uint,
  373. appName string,
  374. deploymentTargetID string,
  375. variables map[string]string,
  376. secrets map[string]string,
  377. Base64AppProto string,
  378. ) (*porter_app.UpdateAppEnvironmentResponse, error) {
  379. resp := &porter_app.UpdateAppEnvironmentResponse{}
  380. req := &porter_app.UpdateAppEnvironmentRequest{
  381. DeploymentTargetID: deploymentTargetID,
  382. Variables: variables,
  383. Secrets: secrets,
  384. HardUpdate: false,
  385. Base64AppProto: Base64AppProto,
  386. }
  387. err := c.postRequest(
  388. fmt.Sprintf(
  389. "/projects/%d/clusters/%d/apps/%s/update-environment",
  390. projectID, clusterID, appName,
  391. ),
  392. req,
  393. resp,
  394. )
  395. return resp, err
  396. }
  397. // PorterYamlV2Pods gets all pods for a given deployment target id and app name
  398. func (c *Client) PorterYamlV2Pods(
  399. ctx context.Context,
  400. projectID, clusterID uint,
  401. porterAppName string,
  402. req *types.PorterYamlV2PodsRequest,
  403. ) (*types.GetReleaseAllPodsResponse, error) {
  404. resp := &types.GetReleaseAllPodsResponse{}
  405. err := c.getRequest(
  406. fmt.Sprintf(
  407. "/projects/%d/clusters/%d/apps/%s/pods",
  408. projectID, clusterID,
  409. porterAppName,
  410. ),
  411. req,
  412. resp,
  413. )
  414. return resp, err
  415. }
  416. // UpdateImage updates the image for a porter app (porter yaml v2 only)
  417. func (c *Client) UpdateImage(
  418. ctx context.Context,
  419. projectID, clusterID uint,
  420. appName, deploymentTargetId, tag string,
  421. ) (*porter_app.UpdateImageResponse, error) {
  422. req := &porter_app.UpdateImageRequest{
  423. Tag: tag,
  424. DeploymentTargetId: deploymentTargetId,
  425. }
  426. resp := &porter_app.UpdateImageResponse{}
  427. err := c.postRequest(
  428. fmt.Sprintf(
  429. "/projects/%d/clusters/%d/apps/%s/update-image",
  430. projectID, clusterID, appName,
  431. ),
  432. &req,
  433. resp,
  434. )
  435. return resp, err
  436. }