Skip to content

Commit

Permalink
Merge pull request #10 from holos-run/jeff/kargo
Browse files Browse the repository at this point in the history
Kargo Integration
  • Loading branch information
jeffmccune authored Dec 5, 2024
2 parents b697cee + 9ee2fe1 commit 7205960
Show file tree
Hide file tree
Showing 222 changed files with 1,999 additions and 9,182 deletions.
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"words": [
"admissionregistration",
"akuity",
"anthos",
"apiextensions",
"applicationset",
"appproject",
Expand Down
37 changes: 20 additions & 17 deletions argocd-application.cue
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,33 @@ import (
#ComponentConfig: {
Name: _
OutputBaseDir: _

// Application resources are Cluster scoped. BuildPlan metadata.name values
// are Project scoped. Construct a unique cluster scoped named to resolve
// conflicts within ArgoCD.
let UniqueName = "\(ProjectName)-\(Name)"
_ArgoAppName: "\(ProjectName)-\(Name)"

// Allow other aspects of the platform configuration to refer to
// `Component._ArgoApplication` to get a handle on the Application resource.
_ArgoApplication: app.#Application & {
metadata: name: _ArgoAppName
metadata: namespace: "argocd"
metadata: labels: Labels
spec: {
destination: server: "https://kubernetes.default.svc"
project: ProjectName
source: {
path: ResourcesPath
repoURL: Organization.RepoURL
targetRevision: string | *"main"
}
}
}

let ArtifactPath = path.Join([OutputBaseDir, "gitops", "\(Name).application.gen.yaml"], path.Unix)
let ResourcesPath = path.Join(["deploy", OutputBaseDir, "components", Name], path.Unix)

// Add the argocd Application instance label to GitOps so resources are in sync.
KustomizeConfig: CommonLabels: "argocd.argoproj.io/instance": UniqueName
KustomizeConfig: CommonLabels: "argocd.argoproj.io/instance": _ArgoAppName

// Labels for the Application itself. We filter the argocd application
// instance label so ArgoCD doesn't think the Application resource manages
Expand All @@ -37,20 +53,7 @@ import (
generators: [{
kind: "Resources"
output: artifact
resources: Application: (UniqueName): app.#Application & {
metadata: name: UniqueName
metadata: namespace: "argocd"
metadata: labels: Labels
spec: {
destination: server: "https://kubernetes.default.svc"
project: ProjectName
source: {
path: ResourcesPath
repoURL: Organization.RepoURL
targetRevision: "main"
}
}
}
resources: Application: (_ArgoAppName): _ArgoApplication
}]
}
}
241 changes: 182 additions & 59 deletions bank-projects.cue
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
@if(!NoBank)
package holos

let BankSecurity = "bank-security"
let BankBackend = "bank-backend"
let BankWeb = "bank-web"

// Platform wide configuration.
BankOfHolos: #BankOfHolos & {
Name: string | *"bank-of-holos"
Expand All @@ -12,90 +16,209 @@ BankOfHolos: #BankOfHolos & {
prod: tier: "prod"
}

EnvironmentNamespaces: {
"bank-frontend": _
"bank-backend": _
"bank-security": _
#BankProject: #Project & {
_kargo_cluster_projects: {[CLUSTER=string]: [NAME=string]: metadata: name: NAME}
}
}

// Projects are security boundaries, so manage one project for each environment
// and team combination.
for ENV in BankOfHolos.configuration.environments {
Projects: "\(ENV.name)-bank-security": #ProjectBuilder & {
team: "security"
stack: BankOfHolos.Name
environment: ENV.name
// The security team manages namespaces for the whole stack.
namespaces: BankOfHolos.configuration.environments[ENV.name].namespaces

_components: {
secrets: path: "projects/security/components/bank-secrets"
}
}
// TODO(jeff): Split into prod and nonprod project sets as Gary suggested.
Projects: {
(BankSecurity): #BankProject & {
name: _
clusters: ClusterSets.workload.clusters
team: "security"
// And one special namespace for the Kargo Project for this Holos Project.
// https://docs.kargo.io/how-to-guides/working-with-projects#namespace-adoption
let KargoAdopt = {metadata: labels: "kargo.akuity.io/project": "true"}
namespaces: (BankSecurity): KargoAdopt
namespaces: (BankBackend): KargoAdopt
namespaces: (BankWeb): KargoAdopt

// The security team manages the environment namespaces for the whole stack.
for CLUSTER in clusters {
_kargo_cluster_projects: (CLUSTER.name): (BankSecurity): _
_kargo_cluster_projects: (CLUSTER.name): (BankBackend): _
_kargo_cluster_projects: (CLUSTER.name): (BankWeb): _

let NAMESPACES = #SharedComponent & {
_component: "namespaces"
_project: name
_cluster: CLUSTER.name
_team: team
_stack: Name
}
components: (NAMESPACES.name): NAMESPACES.component

// The projects component digs into Projects.foo._kargo_cluster_projects
// to configure Kargo Project resources.
let PROJECTS = #SharedComponent & {
_component: "projects"
_project: name
_cluster: CLUSTER.name
_team: team
_stack: Name
}
components: (PROJECTS.name): PROJECTS.component

// The stages component digs into Projects.foo._kargo_cluster_projects
// to configure Kargo warehouses and stages for the project.
let STAGES = #ProjectClusterComponent & {
_component: "stages"
_project: name
_cluster: CLUSTER.name
_team: team
_stack: Name
}
components: (STAGES.name): STAGES.component

Projects: "\(ENV.name)-bank-backend": #ProjectBuilder & {
team: "backend"
stack: BankOfHolos.Name
environment: ENV.name

_components: {
// Configuration
"config": path: "projects/bank-backend/components/bank-backend-config"
// Databases
"accounts-db": path: "projects/bank-backend/components/bank-accounts-db"
"ledger-db": path: "projects/bank-backend/components/bank-ledger-db"
// Services
"contacts": path: "projects/bank-backend/components/bank-contacts"
"balance-reader": path: "projects/bank-backend/components/bank-balance-reader"
"userservice": path: "projects/bank-backend/components/bank-userservice"
"ledger-writer": path: "projects/bank-backend/components/bank-ledger-writer"
"transaction-history": path: "projects/bank-backend/components/bank-transaction-history"
for ENV in Environments {
namespaces: BankOfHolos.configuration.environments[ENV.name].namespaces

let BUILDER = #ProjectClusterComponent & {
_project: name
_cluster: CLUSTER.name
_environment: ENV.name
_team: team
_stack: Name
}
let SECRETS = BUILDER & {
_component: "\(ENV.name)-secrets"
component: path: "projects/security/components/bank-secrets"
}
components: (SECRETS.name): SECRETS.component
}
}
}
}

Projects: "\(ENV.name)-bank-web": #ProjectBuilder & {
team: "frontend"
stack: BankOfHolos.Name
environment: ENV.name
(BankBackend): {
name: _
clusters: ClusterSets.workload.clusters
team: "backend"

for CLUSTER in clusters {
for ENV in Environments {
let BUILDER = #ProjectClusterComponent & {
_project: name
_cluster: CLUSTER.name
_environment: ENV.name
_team: team
_stack: Name
}

// Configuration
let CONFIG = BUILDER & {
_component: "\(ENV.name)-bank-backend-config"
component: path: "projects/bank-backend/components/bank-backend-config"
}
components: (CONFIG.name): CONFIG.component

// Databases
let ACCOUNTS_DB = BUILDER & {
_component: "\(ENV.name)-accounts-db"
component: path: "projects/bank-backend/components/bank-accounts-db"
}
components: (ACCOUNTS_DB.name): ACCOUNTS_DB.component

let LEDGER_DB = BUILDER & {
_component: "\(ENV.name)-ledger-db"
component: path: "projects/bank-backend/components/bank-ledger-db"
}
components: (LEDGER_DB.name): LEDGER_DB.component

// Services
let CONTACTS = BUILDER & {
_component: "\(ENV.name)-contacts"
component: path: "projects/bank-backend/components/bank-contacts"
}
components: (CONTACTS.name): CONTACTS.component

_components: {
frontend: path: "projects/bank-frontend/components/bank-frontend"
let BALANCE_READER = BUILDER & {
_component: "\(ENV.name)-balance-reader"
component: path: "projects/bank-backend/components/bank-balance-reader"
}
components: (BALANCE_READER.name): BALANCE_READER.component

let USERSERVICE = BUILDER & {
_component: "\(ENV.name)-userservice"
component: path: "projects/bank-backend/components/bank-userservice"
}
components: (USERSERVICE.name): USERSERVICE.component

let LEDGER_WRITER = BUILDER & {
_component: "\(ENV.name)-ledger-writer"
component: path: "projects/bank-backend/components/bank-ledger-writer"
}
components: (LEDGER_WRITER.name): LEDGER_WRITER.component

let TRANSACTION_HISTORY = BUILDER & {
_component: "\(ENV.name)-transaction-history"
component: path: "projects/bank-backend/components/bank-transaction-history"
}
components: (TRANSACTION_HISTORY.name): TRANSACTION_HISTORY.component
}
}
}
}

// Register the HTTPRoute to the backend Service
if ENV.name == "prod" {
HTTPRoutes: bank: _backendRefs: frontend: namespace: ENV.frontend.namespace
}
if ENV.name != "prod" {
HTTPRoutes: "\(ENV.name)-bank": _backendRefs: frontend: namespace: ENV.frontend.namespace
(BankWeb): {
name: _
clusters: ClusterSets.workload.clusters
team: "frontend"

for CLUSTER in clusters {
for ENV in Environments {
let BUILDER = #ProjectClusterComponent & {
_project: name
_cluster: CLUSTER.name
_environment: ENV.name
_team: team
_stack: Name
}

// Web Frontend
let FRONTEND = BUILDER & {
_component: "\(ENV.name)-frontend"
component: path: "projects/bank-frontend/components/bank-frontend"
}
components: (FRONTEND.name): FRONTEND.component
}
}
}
}
}

// Register the bank projects with the platform.
Projects: BankOfHolos.Projects

// prod httproutes
HTTPRoutes: bank: _backendRefs: frontend: namespace: BankOfHolos.configuration.environments.prod.frontend.namespace
// nonprod httproutes
HTTPRoutes: "dev-bank": _backendRefs: frontend: namespace: BankOfHolos.configuration.environments.dev.frontend.namespace
HTTPRoutes: "test-bank": _backendRefs: frontend: namespace: BankOfHolos.configuration.environments.test.frontend.namespace
HTTPRoutes: "stage-bank": _backendRefs: frontend: namespace: BankOfHolos.configuration.environments.test.frontend.namespace

// Platform wide schema definition.
#BankOfHolos: {
Name: string
// Holos Projects, oriented to Kargo Projects
Projects: #Projects

// Environments to manage.
// Environments to manage in each project.
Environments: #Environments
// Namespaces to manage in each environment.
EnvironmentNamespaces: #NamedObjects

// Configuration constructed from the above fields.
configuration: {
environments: [NAME=string]: {
name: NAME
namespaces: #Namespaces
name: NAME
frontend: namespace: "\(NAME)-bank-frontend"
backend: namespace: "\(NAME)-bank-backend"
security: namespace: "\(NAME)-bank-security"
namespaces: #Namespaces & {
(frontend.namespace): _
(backend.namespace): _
(security.namespace): _
}
}

for ENV in Environments {
for NS in EnvironmentNamespaces {
environments: (ENV.name): namespaces: "\(ENV.name)-\(NS.metadata.name)": _
}
environments: (ENV.name): _
}
}
}
17 changes: 17 additions & 0 deletions components/projects/projects.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package holos

// Produce a kubernetes objects build plan.
holos: Component.BuildPlan

_project: string @tag(project)
_cluster: string @tag(cluster)

Component: #Kubernetes & {
Resources: {
// The kargo.akuity.io/project label is the source of truth for what
// Projects should be managed.
for PROJECT in Projects[_project]._kargo_cluster_projects[_cluster] {
Project: (PROJECT.metadata.name): _
}
}
}
3 changes: 3 additions & 0 deletions components/projects/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Projects

Like Namespaces, but for Kargo Project resources.
Loading

0 comments on commit 7205960

Please sign in to comment.