project.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package models
  2. import (
  3. "fmt"
  4. "gorm.io/gorm"
  5. "github.com/launchdarkly/go-sdk-common/v3/ldcontext"
  6. "github.com/porter-dev/porter/api/types"
  7. "github.com/porter-dev/porter/internal/features"
  8. ints "github.com/porter-dev/porter/internal/models/integrations"
  9. )
  10. // FeatureFlagLabel strongly types project feature flags
  11. type FeatureFlagLabel string
  12. const (
  13. // APITokensEnabled allows users to create Bearer tokens for use with the Porter API
  14. // #nosec G101 - Not actually an api token
  15. APITokensEnabled FeatureFlagLabel = "api_tokens_enabled"
  16. // AzureEnabled enables Azure Provisioning
  17. AzureEnabled FeatureFlagLabel = "azure_enabled"
  18. // CapiProvisionerEnabled enables the CAPI Provisioning flow
  19. CapiProvisionerEnabled FeatureFlagLabel = "capi_provisioner_enabled"
  20. // EnableReprovision enables the provisioning button after initial creation of the cluster
  21. EnableReprovision FeatureFlagLabel = "enable_reprovision"
  22. // FullAddOns shows all addons, not just curated
  23. FullAddOns FeatureFlagLabel = "full_add_ons"
  24. // HelmValuesEnabled shows the helm values tab for porter apps (when simplified_view_enabled=true)
  25. HelmValuesEnabled FeatureFlagLabel = "helm_values_enabled"
  26. // ManagedInfraEnabled uses terraform provisioning instead of capi
  27. ManagedInfraEnabled FeatureFlagLabel = "managed_infra_enabled"
  28. // MultiCluster allows multiple clusters in simplified view (simplified_view_enabled=true)
  29. MultiCluster FeatureFlagLabel = "multi_cluster"
  30. // PreviewEnvsEnabled allows legacy user the ability to see preview environments in sidebar (simplified_view_enabled=false)
  31. PreviewEnvsEnabled FeatureFlagLabel = "preview_envs_enabled"
  32. // RDSDatabasesEnabled allows for users to provision RDS instances within their cluster vpc
  33. RDSDatabasesEnabled FeatureFlagLabel = "rds_databases_enabled"
  34. // SimplifiedViewEnabled shows the new UI dashboard or not
  35. SimplifiedViewEnabled FeatureFlagLabel = "simplified_view_enabled"
  36. // StacksEnabled uses stack view for legacy (simplified_view_enabled=false)
  37. StacksEnabled FeatureFlagLabel = "stacks_enabled"
  38. // ValidateApplyV2 controls whether apps deploys use a porter app revision contract vs helm
  39. ValidateApplyV2 FeatureFlagLabel = "validate_apply_v2"
  40. )
  41. // ProjectFeatureFlags keeps track of all project-related feature flags
  42. var ProjectFeatureFlags = map[FeatureFlagLabel]bool{
  43. APITokensEnabled: false,
  44. AzureEnabled: false,
  45. CapiProvisionerEnabled: true,
  46. EnableReprovision: false,
  47. FullAddOns: false,
  48. HelmValuesEnabled: false,
  49. ManagedInfraEnabled: false,
  50. MultiCluster: false,
  51. PreviewEnvsEnabled: false,
  52. RDSDatabasesEnabled: false,
  53. SimplifiedViewEnabled: true,
  54. StacksEnabled: false,
  55. ValidateApplyV2: false,
  56. }
  57. type ProjectPlan string
  58. const (
  59. ProjectPlanBasic ProjectPlan = "basic"
  60. ProjectPlanTeam ProjectPlan = "team"
  61. ProjectPlanGrowth ProjectPlan = "growth"
  62. ProjectPlanEnterprise ProjectPlan = "enterprise"
  63. )
  64. // Project type that extends gorm.Model
  65. type Project struct {
  66. gorm.Model `gorm:"embedded"`
  67. Name string `json:"name"`
  68. Roles []Role `json:"roles"`
  69. ProjectUsageID uint
  70. ProjectUsageCacheID uint
  71. // linked repos
  72. GitRepos []GitRepo `json:"git_repos,omitempty"`
  73. // linked registries
  74. Registries []Registry `json:"registries,omitempty"`
  75. // linked clusters
  76. Clusters []Cluster `json:"clusters"`
  77. ClusterCandidates []ClusterCandidate `json:"cluster_candidates"`
  78. // linked databases
  79. Databases []Database `json:"databases"`
  80. // linked helm repos
  81. HelmRepos []HelmRepo `json:"helm_repos"`
  82. // invitations to the project
  83. Invites []Invite `json:"invites"`
  84. // provisioned aws infra
  85. Infras []Infra `json:"infras"`
  86. // auth mechanisms
  87. KubeIntegrations []ints.KubeIntegration `json:"kube_integrations"`
  88. BasicIntegrations []ints.BasicIntegration `json:"basic_integrations"`
  89. OIDCIntegrations []ints.OIDCIntegration `json:"oidc_integrations"`
  90. OAuthIntegrations []ints.OAuthIntegration `json:"oauth_integrations"`
  91. AWSIntegrations []ints.AWSIntegration `json:"aws_integrations"`
  92. GCPIntegrations []ints.GCPIntegration `json:"gcp_integrations"`
  93. AzureIntegrations []ints.AzureIntegration `json:"azure_integrations"`
  94. GitlabIntegrations []ints.GitlabIntegration `json:"gitlab_integrations"`
  95. // Deprecated: use p.GetFeatureFlag(PreviewEnvsEnabled, *features.Client) instead
  96. PreviewEnvsEnabled bool
  97. // Deprecated: use p.GetFeatureFlag(RDSDatabasesEnabled, *features.Client) instead
  98. RDSDatabasesEnabled bool
  99. // Deprecated: use p.GetFeatureFlag(ManagedInfraEnabled, *features.Client) instead
  100. ManagedInfraEnabled bool
  101. // Deprecated: use p.GetFeatureFlag(StacksEnabled, *features.Client) instead
  102. StacksEnabled bool
  103. // Deprecated: use p.GetFeatureFlag(APITokensEnabled, *features.Client) instead
  104. APITokensEnabled bool
  105. // Deprecated: use p.GetFeatureFlag(CapiProvisionerEnabled, *features.Client) instead
  106. CapiProvisionerEnabled bool
  107. // Deprecated: use p.GetFeatureFlag(SimplifiedViewEnabled, *features.Client) instead
  108. SimplifiedViewEnabled bool
  109. // Deprecated: use p.GetFeatureFlag(AzureEnabled, *features.Client) instead
  110. AzureEnabled bool
  111. // Deprecated: use p.GetFeatureFlag(HelmValuesEnabled, *features.Client) instead
  112. HelmValuesEnabled bool
  113. // Deprecated: use p.GetFeatureFlag(MultiCluster, *features.Client) instead
  114. MultiCluster bool `gorm:"default:false"`
  115. // Deprecated: use p.GetFeatureFlag(FullAddOns, *features.Client) instead
  116. FullAddOns bool `gorm:"default:false"`
  117. // Deprecated: use p.GetFeatureFlag(ValidateApplyV2, *features.Client) instead
  118. ValidateApplyV2 bool `gorm:"default:false"`
  119. // Deprecated: use p.GetFeatureFlag(EnableReprovision, *features.Client) instead
  120. EnableReprovision bool `gorm:"default:false"`
  121. }
  122. // GetFeatureFlag calls launchdarkly for the specified flag
  123. // and returns the configured value
  124. func (p *Project) GetFeatureFlag(flagName FeatureFlagLabel, launchDarklyClient *features.Client) bool {
  125. projectID := p.ID
  126. projectName := p.Name
  127. ldContext := getProjectContext(projectID, projectName)
  128. defaultValue := ProjectFeatureFlags[flagName]
  129. value, _ := launchDarklyClient.BoolVariation(string(flagName), ldContext, defaultValue)
  130. return value
  131. }
  132. // ToProjectType generates an external types.Project to be shared over REST
  133. func (p *Project) ToProjectType(launchDarklyClient *features.Client) types.Project {
  134. roles := make([]*types.Role, 0)
  135. for _, role := range p.Roles {
  136. roles = append(roles, role.ToRoleType())
  137. }
  138. projectID := p.ID
  139. projectName := p.Name
  140. return types.Project{
  141. ID: projectID,
  142. Name: projectName,
  143. Roles: roles,
  144. PreviewEnvsEnabled: p.GetFeatureFlag(PreviewEnvsEnabled, launchDarklyClient),
  145. RDSDatabasesEnabled: p.GetFeatureFlag(RDSDatabasesEnabled, launchDarklyClient),
  146. ManagedInfraEnabled: p.GetFeatureFlag(ManagedInfraEnabled, launchDarklyClient),
  147. StacksEnabled: p.GetFeatureFlag(StacksEnabled, launchDarklyClient),
  148. APITokensEnabled: p.GetFeatureFlag(APITokensEnabled, launchDarklyClient),
  149. CapiProvisionerEnabled: p.GetFeatureFlag(CapiProvisionerEnabled, launchDarklyClient),
  150. SimplifiedViewEnabled: p.GetFeatureFlag(SimplifiedViewEnabled, launchDarklyClient),
  151. AzureEnabled: p.GetFeatureFlag(AzureEnabled, launchDarklyClient),
  152. HelmValuesEnabled: p.GetFeatureFlag(HelmValuesEnabled, launchDarklyClient),
  153. MultiCluster: p.GetFeatureFlag(MultiCluster, launchDarklyClient),
  154. EnableReprovision: p.GetFeatureFlag(EnableReprovision, launchDarklyClient),
  155. ValidateApplyV2: p.GetFeatureFlag(ValidateApplyV2, launchDarklyClient),
  156. FullAddOns: p.GetFeatureFlag(FullAddOns, launchDarklyClient),
  157. }
  158. }
  159. // ToProjectListType returns a "minified" version of a Project
  160. // suitable for api responses to GET /projects
  161. // TODO: update this in the future to use default values for all
  162. // the feature flags instead of trying to retrieve them from the database
  163. func (p *Project) ToProjectListType() *types.ProjectList {
  164. var roles []types.Role
  165. for _, role := range p.Roles {
  166. roles = append(roles, *role.ToRoleType())
  167. }
  168. return &types.ProjectList{
  169. ID: p.ID,
  170. Name: p.Name,
  171. // note: all of these fields should be considered deprecated
  172. // in an api response
  173. Roles: roles,
  174. PreviewEnvsEnabled: p.PreviewEnvsEnabled,
  175. RDSDatabasesEnabled: p.RDSDatabasesEnabled,
  176. ManagedInfraEnabled: p.ManagedInfraEnabled,
  177. StacksEnabled: p.StacksEnabled,
  178. APITokensEnabled: p.APITokensEnabled,
  179. CapiProvisionerEnabled: p.CapiProvisionerEnabled,
  180. SimplifiedViewEnabled: p.SimplifiedViewEnabled,
  181. AzureEnabled: p.AzureEnabled,
  182. HelmValuesEnabled: p.HelmValuesEnabled,
  183. MultiCluster: p.MultiCluster,
  184. EnableReprovision: p.EnableReprovision,
  185. ValidateApplyV2: p.ValidateApplyV2,
  186. FullAddOns: p.FullAddOns,
  187. }
  188. }
  189. func getProjectContext(projectID uint, projectName string) ldcontext.Context {
  190. projectIdentifier := fmt.Sprintf("project-%d", projectID)
  191. launchDarklyName := fmt.Sprintf("%s: %s", projectIdentifier, projectName)
  192. return ldcontext.NewBuilder(projectIdentifier).
  193. Kind("project").
  194. Name(launchDarklyName).
  195. SetInt("project_id", int(projectID)).
  196. Build()
  197. }