project.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package models
  2. import (
  3. "fmt"
  4. "gorm.io/gorm"
  5. "github.com/google/uuid"
  6. "github.com/launchdarkly/go-sdk-common/v3/ldcontext"
  7. "github.com/porter-dev/porter/api/types"
  8. "github.com/porter-dev/porter/internal/features"
  9. ints "github.com/porter-dev/porter/internal/models/integrations"
  10. )
  11. // FeatureFlagLabel strongly types project feature flags
  12. type FeatureFlagLabel string
  13. const (
  14. // APITokensEnabled allows users to create Bearer tokens for use with the Porter API
  15. // #nosec G101 - Not actually an api token
  16. APITokensEnabled FeatureFlagLabel = "api_tokens_enabled"
  17. // AzureEnabled enables Azure Provisioning
  18. AzureEnabled FeatureFlagLabel = "azure_enabled"
  19. // CapiProvisionerEnabled enables the CAPI Provisioning flow
  20. CapiProvisionerEnabled FeatureFlagLabel = "capi_provisioner_enabled"
  21. // BillingEnabled enables the "Billing" tab and all Stripe integrations
  22. BillingEnabled FeatureFlagLabel = "billing_enabled"
  23. // MetronomeEnabled enables all Metronome business logic
  24. MetronomeEnabled FeatureFlagLabel = "metronome_enabled"
  25. // InfisicalEnabled enables the Infisical secrets operator integration
  26. InfisicalEnabled FeatureFlagLabel = "infisical_enabled"
  27. // FreezeEnabled freezes the project
  28. FreezeEnabled FeatureFlagLabel = "freeze_enabled"
  29. // DBEnabled enables the "Databases" tab
  30. DBEnabled FeatureFlagLabel = "db_enabled"
  31. // EFSEnabled enables the "EFS" checkbox in App Settings
  32. EFSEnabled FeatureFlagLabel = "efs_enabled"
  33. // EnableReprovision enables the provisioning button after initial creation of the cluster
  34. EnableReprovision FeatureFlagLabel = "enable_reprovision"
  35. // FullAddOns shows all addons, not just curated
  36. FullAddOns FeatureFlagLabel = "full_add_ons"
  37. // GPUEnabled enables the "GPU for users"
  38. GPUEnabled FeatureFlagLabel = "gpu_enabled"
  39. // HelmValuesEnabled shows the helm values tab for porter apps (when simplified_view_enabled=true)
  40. HelmValuesEnabled FeatureFlagLabel = "helm_values_enabled"
  41. // ManagedInfraEnabled uses terraform provisioning instead of capi
  42. ManagedInfraEnabled FeatureFlagLabel = "managed_infra_enabled"
  43. // MultiCluster allows multiple clusters in simplified view (simplified_view_enabled=true)
  44. MultiCluster FeatureFlagLabel = "multi_cluster"
  45. // PreviewEnvsEnabled allows legacy user the ability to see preview environments in sidebar (simplified_view_enabled=false)
  46. PreviewEnvsEnabled FeatureFlagLabel = "preview_envs_enabled"
  47. // RDSDatabasesEnabled allows for users to provision RDS instances within their cluster vpc
  48. RDSDatabasesEnabled FeatureFlagLabel = "rds_databases_enabled"
  49. // QuotaIncrease enables whether we allow for auto increase of quota_increase
  50. QuotaIncrease FeatureFlagLabel = "quota_increase"
  51. // SimplifiedViewEnabled shows the new UI dashboard or not
  52. SimplifiedViewEnabled FeatureFlagLabel = "simplified_view_enabled"
  53. // SOC2ControlsEnabled decides on whether the SOC2 Compliance UI is shown on the infrastructure tab
  54. SOC2ControlsEnabled FeatureFlagLabel = "soc2_controls_enabled"
  55. // StacksEnabled uses stack view for legacy (simplified_view_enabled=false)
  56. StacksEnabled FeatureFlagLabel = "stacks_enabled"
  57. // ValidateApplyV2 controls whether apps deploys use a porter app revision contract vs helm
  58. ValidateApplyV2 FeatureFlagLabel = "validate_apply_v2"
  59. // BetaFeaturesEnabled controls whether a project uses beta features
  60. BetaFeaturesEnabled FeatureFlagLabel = "beta_features_enabled"
  61. // AWSACKAuthEnabled controls whether a project's AWS access is governed through AWS ACK
  62. AWSACKAuthEnabled FeatureFlagLabel = "aws_ack_auth_enabled"
  63. // ManagedDeploymentTargetsEnabled controls whether a project can use managed deployment targets
  64. ManagedDeploymentTargetsEnabled FeatureFlagLabel = "managed_deployment_targets_enabled"
  65. // AdvancedInfraEnabled controls whether a project can use advanced infrastructure settings
  66. AdvancedInfraEnabled FeatureFlagLabel = "advanced_infra_enabled"
  67. // AdvancedRbacEnabled controls whether a project can use advanced rbac settings
  68. AdvancedRbacEnabled FeatureFlagLabel = "advanced_rbac_enabled"
  69. )
  70. // ProjectFeatureFlags keeps track of all project-related feature flags
  71. var ProjectFeatureFlags = map[FeatureFlagLabel]bool{
  72. APITokensEnabled: false,
  73. AWSACKAuthEnabled: false,
  74. AzureEnabled: false,
  75. BetaFeaturesEnabled: false,
  76. CapiProvisionerEnabled: true,
  77. BillingEnabled: false,
  78. MetronomeEnabled: false,
  79. InfisicalEnabled: false,
  80. FreezeEnabled: false,
  81. DBEnabled: false,
  82. EFSEnabled: false,
  83. EnableReprovision: false,
  84. FullAddOns: false,
  85. GPUEnabled: false,
  86. HelmValuesEnabled: false,
  87. ManagedInfraEnabled: false,
  88. MultiCluster: false,
  89. PreviewEnvsEnabled: false,
  90. QuotaIncrease: false,
  91. RDSDatabasesEnabled: false,
  92. SimplifiedViewEnabled: true,
  93. SOC2ControlsEnabled: false,
  94. StacksEnabled: false,
  95. ValidateApplyV2: true,
  96. ManagedDeploymentTargetsEnabled: false,
  97. AdvancedInfraEnabled: false,
  98. AdvancedRbacEnabled: false,
  99. }
  100. type ProjectPlan string
  101. const (
  102. ProjectPlanBasic ProjectPlan = "basic"
  103. ProjectPlanTeam ProjectPlan = "team"
  104. ProjectPlanGrowth ProjectPlan = "growth"
  105. ProjectPlanEnterprise ProjectPlan = "enterprise"
  106. )
  107. // Project type that extends gorm.Model
  108. type Project struct {
  109. gorm.Model `gorm:"embedded"`
  110. Name string `json:"name"`
  111. Roles []Role `json:"roles"`
  112. // BillingID corresponds to the id generated by the billing provider
  113. BillingID string
  114. BillingEnabled bool
  115. // UsageID is the id corresponding to the customer in Metronome
  116. UsageID uuid.UUID
  117. // UsagePlanID is the id of the customer-plan relationship. Do not confuse with the actual plan ID.
  118. // This exists as long as a user is part of a plan.
  119. UsagePlanID uuid.UUID
  120. // linked repos
  121. GitRepos []GitRepo `json:"git_repos,omitempty"`
  122. // linked registries
  123. Registries []Registry `json:"registries,omitempty"`
  124. // linked clusters
  125. Clusters []Cluster `json:"clusters"`
  126. ClusterCandidates []ClusterCandidate `json:"cluster_candidates"`
  127. // linked databases
  128. Databases []Database `json:"databases"`
  129. // linked helm repos
  130. HelmRepos []HelmRepo `json:"helm_repos"`
  131. // invitations to the project
  132. Invites []Invite `json:"invites"`
  133. // provisioned aws infra
  134. Infras []Infra `json:"infras"`
  135. // auth mechanisms
  136. KubeIntegrations []ints.KubeIntegration `json:"kube_integrations"`
  137. BasicIntegrations []ints.BasicIntegration `json:"basic_integrations"`
  138. OIDCIntegrations []ints.OIDCIntegration `json:"oidc_integrations"`
  139. OAuthIntegrations []ints.OAuthIntegration `json:"oauth_integrations"`
  140. AWSIntegrations []ints.AWSIntegration `json:"aws_integrations"`
  141. GCPIntegrations []ints.GCPIntegration `json:"gcp_integrations"`
  142. AzureIntegrations []ints.AzureIntegration `json:"azure_integrations"`
  143. GitlabIntegrations []ints.GitlabIntegration `json:"gitlab_integrations"`
  144. // Deprecated: use p.GetFeatureFlag(PreviewEnvsEnabled, *features.Client) instead
  145. PreviewEnvsEnabled bool
  146. // Deprecated: use p.GetFeatureFlag(RDSDatabasesEnabled, *features.Client) instead
  147. RDSDatabasesEnabled bool
  148. // Deprecated: use p.GetFeatureFlag(ManagedInfraEnabled, *features.Client) instead
  149. ManagedInfraEnabled bool
  150. // Deprecated: use p.GetFeatureFlag(StacksEnabled, *features.Client) instead
  151. StacksEnabled bool
  152. // Deprecated: use p.GetFeatureFlag(APITokensEnabled, *features.Client) instead
  153. APITokensEnabled bool
  154. // Deprecated: use p.GetFeatureFlag(CapiProvisionerEnabled, *features.Client) instead
  155. CapiProvisionerEnabled bool
  156. // Deprecated: use p.GetFeatureFlag(SimplifiedViewEnabled, *features.Client) instead
  157. SimplifiedViewEnabled bool
  158. // Deprecated: use p.GetFeatureFlag(AzureEnabled, *features.Client) instead
  159. AzureEnabled bool
  160. // Deprecated: use p.GetFeatureFlag(HelmValuesEnabled, *features.Client) instead
  161. HelmValuesEnabled bool
  162. // Deprecated: use p.GetFeatureFlag(MultiCluster, *features.Client) instead
  163. MultiCluster bool `gorm:"default:false"`
  164. // Deprecated: use p.GetFeatureFlag(FullAddOns, *features.Client) instead
  165. FullAddOns bool `gorm:"default:false"`
  166. // Deprecated: use p.GetFeatureFlag(ValidateApplyV2, *features.Client) instead
  167. ValidateApplyV2 bool `gorm:"default:false"`
  168. // Deprecated: use p.GetFeatureFlag(EnableReprovision, *features.Client) instead
  169. EnableSandbox bool `gorm:"default:false"`
  170. EnableReprovision bool `gorm:"default:false"`
  171. AdvancedInfraEnabled bool `gorm:"default:false"`
  172. AdvancedRbacEnabled bool `gorm:"default:false"`
  173. // ReferralCode is a unique code that can be shared to referr other users to Porter
  174. ReferralCode string
  175. // Referrals is a list of users that have been referred by this project's code
  176. Referrals []Referral `json:"referrals"`
  177. }
  178. // GetFeatureFlag calls launchdarkly for the specified flag
  179. // and returns the configured value
  180. func (p *Project) GetFeatureFlag(flagName FeatureFlagLabel, launchDarklyClient *features.Client) bool {
  181. if launchDarklyClient.UseDatabase() {
  182. // case switch things
  183. switch flagName {
  184. case "api_tokens_enabled":
  185. return p.APITokensEnabled
  186. case "azure_enabled":
  187. return p.AzureEnabled
  188. case "capi_provisioner_enabled":
  189. return p.CapiProvisionerEnabled
  190. case "billing_enabled":
  191. return p.BillingEnabled
  192. case "db_enabled":
  193. return false
  194. case "enable_reprovision":
  195. return p.EnableReprovision
  196. case "full_add_ons":
  197. return p.FullAddOns
  198. case "gpu_enabled":
  199. return false
  200. case "helm_values_enabled":
  201. return p.HelmValuesEnabled
  202. case "managed_infra_enabled":
  203. return p.ManagedInfraEnabled
  204. case "multi_cluster":
  205. return p.MultiCluster
  206. case "preview_envs_enabled":
  207. return p.PreviewEnvsEnabled
  208. case "quota_increase":
  209. return false
  210. case "rds_databases_enabled":
  211. return p.RDSDatabasesEnabled
  212. case "simplified_view_enabled":
  213. return p.SimplifiedViewEnabled
  214. case "soc2_controls_enabled":
  215. return false
  216. case "stacks_enabled":
  217. return p.StacksEnabled
  218. case "validate_apply_v2":
  219. return p.ValidateApplyV2
  220. case "efs_enabled":
  221. return false
  222. case "aws_ack_auth_enabled":
  223. return false
  224. case "advanced_infra_enabled":
  225. return false
  226. case "advanced_rbac_enabled":
  227. return p.AdvancedRbacEnabled
  228. }
  229. }
  230. projectID := p.ID
  231. projectName := p.Name
  232. ldContext := getProjectContext(projectID, projectName)
  233. defaultValue := ProjectFeatureFlags[flagName]
  234. value, _ := launchDarklyClient.BoolVariation(string(flagName), ldContext, defaultValue)
  235. return value
  236. }
  237. // ToProjectType generates an external types.Project to be shared over REST
  238. func (p *Project) ToProjectType(launchDarklyClient *features.Client) types.Project {
  239. roles := make([]*types.Role, 0)
  240. for _, role := range p.Roles {
  241. roles = append(roles, role.ToRoleType())
  242. }
  243. projectID := p.ID
  244. projectName := p.Name
  245. return types.Project{
  246. ID: projectID,
  247. Name: projectName,
  248. Roles: roles,
  249. APITokensEnabled: p.GetFeatureFlag(APITokensEnabled, launchDarklyClient),
  250. AWSACKAuthEnabled: p.GetFeatureFlag(AWSACKAuthEnabled, launchDarklyClient),
  251. AzureEnabled: p.GetFeatureFlag(AzureEnabled, launchDarklyClient),
  252. BetaFeaturesEnabled: p.GetFeatureFlag(BetaFeaturesEnabled, launchDarklyClient),
  253. CapiProvisionerEnabled: p.GetFeatureFlag(CapiProvisionerEnabled, launchDarklyClient),
  254. BillingEnabled: p.GetFeatureFlag(BillingEnabled, launchDarklyClient),
  255. MetronomeEnabled: p.GetFeatureFlag(MetronomeEnabled, launchDarklyClient),
  256. InfisicalEnabled: p.GetFeatureFlag(InfisicalEnabled, launchDarklyClient),
  257. FreezeEnabled: p.GetFeatureFlag(FreezeEnabled, launchDarklyClient),
  258. DBEnabled: p.GetFeatureFlag(DBEnabled, launchDarklyClient),
  259. EFSEnabled: p.GetFeatureFlag(EFSEnabled, launchDarklyClient),
  260. EnableReprovision: p.GetFeatureFlag(EnableReprovision, launchDarklyClient),
  261. FullAddOns: p.GetFeatureFlag(FullAddOns, launchDarklyClient),
  262. GPUEnabled: p.GetFeatureFlag(GPUEnabled, launchDarklyClient),
  263. HelmValuesEnabled: p.GetFeatureFlag(HelmValuesEnabled, launchDarklyClient),
  264. ManagedInfraEnabled: p.GetFeatureFlag(ManagedInfraEnabled, launchDarklyClient),
  265. MultiCluster: p.GetFeatureFlag(MultiCluster, launchDarklyClient),
  266. PreviewEnvsEnabled: p.GetFeatureFlag(PreviewEnvsEnabled, launchDarklyClient),
  267. QuotaIncrease: p.GetFeatureFlag(QuotaIncrease, launchDarklyClient),
  268. RDSDatabasesEnabled: p.GetFeatureFlag(RDSDatabasesEnabled, launchDarklyClient),
  269. SimplifiedViewEnabled: p.GetFeatureFlag(SimplifiedViewEnabled, launchDarklyClient),
  270. SOC2ControlsEnabled: p.GetFeatureFlag(SOC2ControlsEnabled, launchDarklyClient),
  271. StacksEnabled: p.GetFeatureFlag(StacksEnabled, launchDarklyClient),
  272. ValidateApplyV2: p.GetFeatureFlag(ValidateApplyV2, launchDarklyClient),
  273. ManagedDeploymentTargetsEnabled: p.GetFeatureFlag(ManagedDeploymentTargetsEnabled, launchDarklyClient),
  274. AdvancedInfraEnabled: p.GetFeatureFlag(AdvancedInfraEnabled, launchDarklyClient),
  275. SandboxEnabled: p.EnableSandbox,
  276. AdvancedRbacEnabled: p.GetFeatureFlag(AdvancedRbacEnabled, launchDarklyClient),
  277. ReferralCode: p.ReferralCode,
  278. }
  279. }
  280. // ToProjectListType returns a "minified" version of a Project
  281. // suitable for api responses to GET /projects
  282. // TODO: update this in the future to use default values for all
  283. // the feature flags instead of trying to retrieve them from the database
  284. func (p *Project) ToProjectListType() *types.ProjectList {
  285. var roles []types.Role
  286. for _, role := range p.Roles {
  287. roles = append(roles, *role.ToRoleType())
  288. }
  289. return &types.ProjectList{
  290. ID: p.ID,
  291. Name: p.Name,
  292. // note: all of these fields should be considered deprecated
  293. // in an api response
  294. Roles: roles,
  295. BillingEnabled: p.BillingEnabled,
  296. PreviewEnvsEnabled: p.PreviewEnvsEnabled,
  297. RDSDatabasesEnabled: p.RDSDatabasesEnabled,
  298. ManagedInfraEnabled: p.ManagedInfraEnabled,
  299. StacksEnabled: p.StacksEnabled,
  300. APITokensEnabled: p.APITokensEnabled,
  301. DBEnabled: false,
  302. CapiProvisionerEnabled: p.CapiProvisionerEnabled,
  303. SimplifiedViewEnabled: p.SimplifiedViewEnabled,
  304. AzureEnabled: p.AzureEnabled,
  305. HelmValuesEnabled: p.HelmValuesEnabled,
  306. MultiCluster: p.MultiCluster,
  307. EnableReprovision: p.EnableReprovision,
  308. ValidateApplyV2: p.ValidateApplyV2,
  309. FullAddOns: p.FullAddOns,
  310. AdvancedInfraEnabled: p.AdvancedInfraEnabled,
  311. AdvancedRbacEnabled: p.AdvancedRbacEnabled,
  312. }
  313. }
  314. func getProjectContext(projectID uint, projectName string) ldcontext.Context {
  315. projectIdentifier := fmt.Sprintf("project-%d", projectID)
  316. launchDarklyName := fmt.Sprintf("%s: %s", projectIdentifier, projectName)
  317. return ldcontext.NewBuilder(projectIdentifier).
  318. Kind("project").
  319. Name(launchDarklyName).
  320. SetInt("project_id", int(projectID)).
  321. Build()
  322. }