1 // Package gcpinfra defines the GCP Resource Manager / Cloud resource structure that 2 // is used to manage all infrastructure owned by Edge. 3 // Initial RFC: https://docs.edge-infra.dev/rfc/gcp-infra-structure 4 package gcpinfra 5 6 import ( 7 "fmt" 8 "strings" 9 10 "edge-infra.dev/pkg/lib/gcp/project" 11 ) 12 13 // String constants. These won't change across Instances/Instance Groups, 14 // so they aren't defaults (see defaults.go) 15 var ( 16 // ForemanServiceAccountName is the name used for all Foreman GCP SAs 17 ForemanServiceAccountName = "foreman-cnrm-system" 18 // ProjectIDPrefix is the string that must begin all GCP Project IDs 19 // owned by Edge, per NCR GCP Org requirements. We think it is as silly 20 // as you do. 21 ProjectIDPrefix = "ret-edge" 22 // InfraFolderName is the folder name that contains the Infra GCP project 23 // for an InstanceGroup 24 InfraFolderName = "infra" 25 ) 26 27 // RootFolder is The root folder that Edge owns, containing all instances 28 // (dev, stage, test, prod, etc) and Edge infrastructure 29 type RootFolder struct { 30 FolderID string 31 InstanceGroups []InstanceGroup 32 } 33 34 // InstanceGroup contains a group of individual Edge instances, each sharing 35 // common platform infrastructure, defined in InstanceGroup.Infra 36 type InstanceGroup struct { 37 FolderID string `yaml:"folderId"` 38 Name string `yaml:"name"` 39 Instances []Instance `yaml:"instances,omitempty"` 40 Infra Infra `yaml:"infra,omitempty"` 41 } 42 43 // Infra is the folder + project that owns the billing admin Foreman Service 44 // Account needed by each Instance to create tenant projects. Other infrastructure 45 // shared by instances is also defined here, such as: GCR registries, DNS, etc. 46 type Infra struct { 47 FolderID string `yaml:"folderId"` 48 ProjectID string `yaml:"projectId,omitempty"` 49 ForemanServiceAccount string `yaml:"foremanSvcAct,omitempty"` 50 } 51 52 // Instance is the GCP infra needed for a single Edge instance. If a 53 // Namespace is provided, an additional folder will be created that the instance 54 // is nested in. 55 type Instance struct { 56 // The instance name. 57 Name string `yaml:"name"` 58 // Abstract logical grouping of instsances, e.g., dev, test, sandbox 59 Namespace string `yaml:"namespace,omitempty"` 60 // List of tenant projects registered with this instance of Edge 61 Tenants []Tenant `yaml:"tenants,omitempty"` 62 // The GCP project where the Edge control plane will be deployed 63 ForemanProjectID string `yaml:"foremanProjectId,omitempty"` 64 // QLIDs that will be given admin privileges on the instance and permissions 65 // to manage the instance K8s resources on the platform infrastructure cluster 66 Owners []string `yaml:"owners,omitempty"` 67 } 68 69 // Tenant represents a tenant's GCP infra. 70 type Tenant struct { 71 ProjectID string 72 } 73 74 // ForemanProjectID creates + validates a Project ID string for an instance's 75 // Foreman GCP Project 76 func ForemanProjectID(name string) (string, error) { 77 id := fmt.Sprintf("%s-%s-foreman", ProjectIDPrefix, name) 78 err := project.IsValidProjectID(id) 79 if err != nil { 80 return "", fmt.Errorf("gcpinfra.ForemanProjectID: %w", err) 81 } 82 return id, nil 83 } 84 85 var ErrMissingPrefix = fmt.Errorf("project ID is missing required prefix %s", ProjectIDPrefix) 86 87 // IsValidForemanProjectID validates input project ID strings based on org 88 // naming requirements (constant prefix) and GCP requirements 89 func IsValidForemanProjectID(id string) error { 90 if !strings.HasPrefix(id, ProjectIDPrefix) { 91 return fmt.Errorf("gcpinfra: invalid id %s. error: %w", id, ErrMissingPrefix) 92 } 93 if err := project.IsValidProjectID(id); err != nil { 94 return fmt.Errorf("gcpinfra: project id %s invalid: error: %w", id, err) 95 } 96 97 return nil 98 } 99