// Package gcpinfra defines the GCP Resource Manager / Cloud resource structure that // is used to manage all infrastructure owned by Edge. // Initial RFC: https://docs.edge-infra.dev/rfc/gcp-infra-structure package gcpinfra import ( "fmt" "strings" "edge-infra.dev/pkg/lib/gcp/project" ) // String constants. These won't change across Instances/Instance Groups, // so they aren't defaults (see defaults.go) var ( // ForemanServiceAccountName is the name used for all Foreman GCP SAs ForemanServiceAccountName = "foreman-cnrm-system" // ProjectIDPrefix is the string that must begin all GCP Project IDs // owned by Edge, per NCR GCP Org requirements. We think it is as silly // as you do. ProjectIDPrefix = "ret-edge" // InfraFolderName is the folder name that contains the Infra GCP project // for an InstanceGroup InfraFolderName = "infra" ) // RootFolder is The root folder that Edge owns, containing all instances // (dev, stage, test, prod, etc) and Edge infrastructure type RootFolder struct { FolderID string InstanceGroups []InstanceGroup } // InstanceGroup contains a group of individual Edge instances, each sharing // common platform infrastructure, defined in InstanceGroup.Infra type InstanceGroup struct { FolderID string `yaml:"folderId"` Name string `yaml:"name"` Instances []Instance `yaml:"instances,omitempty"` Infra Infra `yaml:"infra,omitempty"` } // Infra is the folder + project that owns the billing admin Foreman Service // Account needed by each Instance to create tenant projects. Other infrastructure // shared by instances is also defined here, such as: GCR registries, DNS, etc. type Infra struct { FolderID string `yaml:"folderId"` ProjectID string `yaml:"projectId,omitempty"` ForemanServiceAccount string `yaml:"foremanSvcAct,omitempty"` } // Instance is the GCP infra needed for a single Edge instance. If a // Namespace is provided, an additional folder will be created that the instance // is nested in. type Instance struct { // The instance name. Name string `yaml:"name"` // Abstract logical grouping of instsances, e.g., dev, test, sandbox Namespace string `yaml:"namespace,omitempty"` // List of tenant projects registered with this instance of Edge Tenants []Tenant `yaml:"tenants,omitempty"` // The GCP project where the Edge control plane will be deployed ForemanProjectID string `yaml:"foremanProjectId,omitempty"` // QLIDs that will be given admin privileges on the instance and permissions // to manage the instance K8s resources on the platform infrastructure cluster Owners []string `yaml:"owners,omitempty"` } // Tenant represents a tenant's GCP infra. type Tenant struct { ProjectID string } // ForemanProjectID creates + validates a Project ID string for an instance's // Foreman GCP Project func ForemanProjectID(name string) (string, error) { id := fmt.Sprintf("%s-%s-foreman", ProjectIDPrefix, name) err := project.IsValidProjectID(id) if err != nil { return "", fmt.Errorf("gcpinfra.ForemanProjectID: %w", err) } return id, nil } var ErrMissingPrefix = fmt.Errorf("project ID is missing required prefix %s", ProjectIDPrefix) // IsValidForemanProjectID validates input project ID strings based on org // naming requirements (constant prefix) and GCP requirements func IsValidForemanProjectID(id string) error { if !strings.HasPrefix(id, ProjectIDPrefix) { return fmt.Errorf("gcpinfra: invalid id %s. error: %w", id, ErrMissingPrefix) } if err := project.IsValidProjectID(id); err != nil { return fmt.Errorf("gcpinfra: project id %s invalid: error: %w", id, err) } return nil }