initial acm config
This commit is contained in:
4
tmp/acm-hub-bootstrap-old/.gitignore
vendored
Normal file
4
tmp/acm-hub-bootstrap-old/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
sealed-secrets-key.yaml
|
||||
slack-token-key.yaml
|
||||
*-private.yaml
|
||||
eso-token-*.yaml
|
||||
38
tmp/acm-hub-bootstrap-old/README.md
Normal file
38
tmp/acm-hub-bootstrap-old/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
### Introduction
|
||||
|
||||
This repository is used to bootstrap the RHACM Hub cluster as well as hold the ACM configuration
|
||||
I use in my homelab environment. It is referenced by the [cluster-config](https://github.com/gnunn-gitops/cluster-config) repo for the `local.hub` cluster's ACM applications (Hub, Policies and Observerability).
|
||||
|
||||
From the perspective of bootstrapping the Hub there are a couple of different ways to go. You could
|
||||
manually install OpenShift GitOps and have it bootstrap everything on the Hub including RHACM. However while
|
||||
I did consider that approach I'm using ACM to bootstrap my managed clusters and I wanted to use the exact same workflow
|
||||
if I could for the Hub. This is because I wanted to avoid having to create a tweaked workflow just for the Hub.
|
||||
|
||||
### Bootstrap Process
|
||||
|
||||
The bootstrap process, encapsulated in the `bootstrap.sh` script, is as follows:
|
||||
|
||||
1. Install the RHACM operator and wait for it to complete
|
||||
2. Install the MultiClusterHub custom resource and wait for it to be in the Running phase
|
||||
3. Deploy all of the RHACM policies including the policy that deploys the OpenShift
|
||||
GitOps operator with the bootstrap application
|
||||
4. Label the Hub cluster, `local-cluster`, with the label `gitops=local.hub`. This trigger the
|
||||
GitOps policy we deployed in step #3 to install OpenShift GitOps on the Hub cluster and
|
||||
deploy the bootstrap application pointing to the repo and path needed for this cluster, i.e.
|
||||
`local.home`
|
||||
|
||||
At this point the GitOps operator deploys everything the Hub cluster requires including storage, operators, etc
|
||||
as well as other ACM components. In particular, the components that the script deployed (Hub + Policies) have
|
||||
Argo applications that will take over managing these.
|
||||
|
||||
With the script bootstrapping the Hub because a one command affair. Once the command completes successfully
|
||||
I walk away for 20-30 minutes while everything gets sorted out.
|
||||
|
||||
### Side-note on LVM Operator
|
||||
|
||||
If you are running a SNO cluster like I am and using the LVM Operator make sure that whatever device you are
|
||||
using for storage with it is free. For example, if you are doing a reinstall of the hub (or other cluster), after
|
||||
the cluster is provisioned but before you provision Day 2 ops ssh to the cluster and run `lsblk` to make sure
|
||||
the device is empty with no partitions.
|
||||
|
||||
A reminder for future me. :)
|
||||
45
tmp/acm-hub-bootstrap-old/bootstrap.sh
Executable file
45
tmp/acm-hub-bootstrap-old/bootstrap.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
LANG=C
|
||||
SLEEP_SECONDS=30
|
||||
|
||||
echo ""
|
||||
echo "Installing RHACM Operator."
|
||||
|
||||
kustomize build github.com/redhat-cop/gitops-catalog/advanced-cluster-management/operator/overlays/release-2.9 | oc apply -f -
|
||||
|
||||
echo "Pause $SLEEP_SECONDS seconds for the creation of the rhacm-operator..."
|
||||
sleep $SLEEP_SECONDS
|
||||
|
||||
echo "Waiting for operator to start"
|
||||
until oc get deployment multiclusterhub-operator -n open-cluster-management
|
||||
do
|
||||
sleep 10;
|
||||
done
|
||||
|
||||
echo "Installing the MultiClusterHub"
|
||||
|
||||
kustomize build github.com/redhat-cop/gitops-catalog/advanced-cluster-management/instance/base | oc apply -f -
|
||||
|
||||
echo "Waiting for hub to be installed"
|
||||
|
||||
until [[ $(oc get multiclusterhub multiclusterhub -n open-cluster-management -o jsonpath='{.status.phase}') == 'Running' ]]
|
||||
do
|
||||
echo "Waiting for hub, current status:"
|
||||
oc get multiclusterhub multiclusterhub -n open-cluster-management
|
||||
sleep 10
|
||||
done
|
||||
|
||||
echo "Installing policies and initial secrets"
|
||||
|
||||
kustomize build bootstrap/secrets/base | oc apply -f -
|
||||
kustomize build bootstrap/policies/overlays/default --enable-alpha-plugins | oc apply -f -
|
||||
|
||||
echo "Labeling cluster with 'gitops: local.home'"
|
||||
oc label managedcluster local-cluster gitops=local.hub --overwrite=true
|
||||
|
||||
echo "Check policy compliance with the following command:"
|
||||
echo " oc get policy -A"
|
||||
|
||||
echo "Once GitOps configuration is complete you may need to run the following to fix Unknown status\n"
|
||||
echo " oc delete secret local-cluster-import -n local-cluster\n"
|
||||
@@ -0,0 +1 @@
|
||||
Experimental, not used at the momentgit add
|
||||
58
tmp/acm-hub-bootstrap-old/bootstrap/install-gitops/setup.sh
Normal file
58
tmp/acm-hub-bootstrap-old/bootstrap/install-gitops/setup.sh
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
LANG=C
|
||||
SLEEP_SECONDS=45
|
||||
|
||||
echo ""
|
||||
echo "Installing GitOps Operator."
|
||||
|
||||
kustomize build ../../components/policies/gitops/base/manifests/gitops-subscription | oc apply -f -
|
||||
|
||||
echo "Pause $SLEEP_SECONDS seconds for the creation of the gitops-operator..."
|
||||
sleep $SLEEP_SECONDS
|
||||
|
||||
echo "Waiting for operator to start"
|
||||
until oc get deployment gitops-operator-controller-manager -n openshift-operators
|
||||
do
|
||||
sleep 5;
|
||||
done
|
||||
|
||||
echo "Waiting for openshift-gitops namespace to be created"
|
||||
until oc get ns openshift-gitops
|
||||
do
|
||||
sleep 5;
|
||||
done
|
||||
|
||||
echo "Waiting for deployments to start"
|
||||
until oc get deployment cluster -n openshift-gitops
|
||||
do
|
||||
sleep 5;
|
||||
done
|
||||
|
||||
echo "Waiting for all pods to be created"
|
||||
deployments=(cluster kam openshift-gitops-applicationset-controller openshift-gitops-redis openshift-gitops-repo-server openshift-gitops-server)
|
||||
for i in "${deployments[@]}";
|
||||
do
|
||||
echo "Waiting for deployment $i";
|
||||
oc rollout status deployment $i -n openshift-gitops
|
||||
done
|
||||
|
||||
echo "Apply overlay to override default instance"
|
||||
# echo "Create default instance of gitops operator"
|
||||
kustomize build ../../components/policies/gitops/base/manifests/gitops-instance/base |
|
||||
yq -y ".spec.repo.env |= map(select(.name == \"INFRASTRUCTURE_ID\").value=\"$INFRASTRUCTURE_ID\")" |
|
||||
yq -y ".spec.repo.env |= map(select(.name == \"CLUSTER_ID\").value=\"$CLUSTER_ID\")" |
|
||||
yq -y ".spec.repo.env |= map(select(.name == \"CLUSTER_NAME\").value=\"$CLUSTER_NAME\")" |
|
||||
yq -y ".spec.repo.env |= map(select(.name == \"SUB_DOMAIN\").value=\"$SUB_DOMAIN\")" |
|
||||
oc apply -f -
|
||||
|
||||
sleep 10
|
||||
echo "Waiting for all pods to redeploy"
|
||||
deployments=(cluster kam openshift-gitops-applicationset-controller openshift-gitops-redis openshift-gitops-repo-server openshift-gitops-server)
|
||||
for i in "${deployments[@]}";
|
||||
do
|
||||
echo "Waiting for deployment $i";
|
||||
oc rollout status deployment $i -n openshift-gitops
|
||||
done
|
||||
|
||||
echo "GitOps Operator ready"
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace: acm-policies
|
||||
|
||||
namespace: acm-policies
|
||||
|
||||
resources:
|
||||
# - ../../../../components/policies/compliance/base
|
||||
- ../../../../components/policies/cert-expiration/base
|
||||
- ../../../../components/policies/gitops/base
|
||||
@@ -0,0 +1 @@
|
||||
Bootstrap tokens for ESO to access Doppler projects, note that these secrets are not in git.
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: hub-secrets
|
||||
@@ -0,0 +1,10 @@
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- hub-secrets-namespace.yaml
|
||||
# Note these secrets are not stored in git and only applied during bootstrap process
|
||||
# They are the tokens for accessing the Doppler secrets SaaS service where secrets are stored
|
||||
- eso-token-cluster-push-secret.yaml
|
||||
- eso-token-cluster-home-secret.yaml
|
||||
- eso-token-cluster-hub-secret.yaml
|
||||
- eso-token-cluster-rhdp-secret.yaml
|
||||
- eso-token-cluster-microshift-secret.yaml
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
annotations:
|
||||
openshift.io/description: ACM Policies
|
||||
openshift.io/display-name: ACM Policies
|
||||
labels:
|
||||
name: acm-policies
|
||||
@@ -0,0 +1,12 @@
|
||||
resources:
|
||||
- github.com/redhat-cop/gitops-catalog/advanced-cluster-management/operator/overlays/release-2.12
|
||||
- github.com/redhat-cop/gitops-catalog/advanced-cluster-management/instance/base
|
||||
|
||||
patches:
|
||||
- patch: |-
|
||||
- op: replace
|
||||
path: /spec/channel
|
||||
value: 'release-2.13'
|
||||
target:
|
||||
kind: Subscription
|
||||
name: advanced-cluster-management
|
||||
@@ -0,0 +1,31 @@
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: observability-metrics-custom-allowlist
|
||||
namespace: open-cluster-management-observability
|
||||
data:
|
||||
metrics_list.yaml: |
|
||||
names:
|
||||
- argocd_cluster_info
|
||||
- argocd-server-metrics
|
||||
- argocd_app_info
|
||||
- argocd_app_sync_total
|
||||
- argocd_app_reconcile_count
|
||||
- argocd_app_reconcile_bucket
|
||||
- argocd_app_k8s_request_total
|
||||
- argocd_kubectl_exec_pending
|
||||
- argocd-metrics
|
||||
- argocd_cluster_api_resource_objects
|
||||
- argocd_cluster_api_resources
|
||||
- argocd_cluster_events_total
|
||||
- argocd_git_request_total
|
||||
- argocd_git_request_duration_seconds_bucket
|
||||
- argocd-repo-server
|
||||
- argocd_redis_request_total
|
||||
- process_start_time_seconds
|
||||
- workqueue_depth
|
||||
- go_memstats_heap_alloc_bytes
|
||||
- process_cpu_seconds_total
|
||||
- go_goroutines
|
||||
- go_gc_duration_seconds
|
||||
- grpc_server_handled_total
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
namespace: open-cluster-management-observability
|
||||
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
labels:
|
||||
grafana-custom-dashboard: "true"
|
||||
|
||||
resources:
|
||||
- github.com/redhat-cop/gitops-catalog/advanced-cluster-management/instance/observability
|
||||
- custom-metrics-allowlist.yaml
|
||||
|
||||
configMapGenerator:
|
||||
- name: gitops-dashboard
|
||||
files:
|
||||
- gitops.json=gitops-dashboard.json
|
||||
|
||||
patches:
|
||||
- patch: |-
|
||||
- op: replace
|
||||
path: /spec/storageConfig/storageClass
|
||||
value: lvms-vg1
|
||||
- op: replace
|
||||
path: /spec/observabilityAddonSpec/interval
|
||||
value: 60
|
||||
- op: add
|
||||
path: /spec/advanced
|
||||
value:
|
||||
alertmanager:
|
||||
replicas: 1
|
||||
grafana:
|
||||
replicas: 1
|
||||
observatoriumAPI:
|
||||
replicas: 1
|
||||
query:
|
||||
replicas: 1
|
||||
queryFrontend:
|
||||
replicas: 1
|
||||
queryFrontendMemcached:
|
||||
replicas: 1
|
||||
rbacQueryProxy:
|
||||
replicas: 1
|
||||
receive:
|
||||
replicas: 1
|
||||
target:
|
||||
kind: MultiClusterObservability
|
||||
name: observability
|
||||
@@ -0,0 +1,3 @@
|
||||
resources:
|
||||
- local-home.yaml
|
||||
- local-hub.yaml
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: cluster.open-cluster-management.io/v1
|
||||
kind: ManagedCluster
|
||||
metadata:
|
||||
annotations:
|
||||
open-cluster-management/created-via: other
|
||||
labels:
|
||||
cloud: Other
|
||||
cluster.open-cluster-management.io/clusterset: dev
|
||||
gitops: local.home
|
||||
color: "0066CC"
|
||||
name: home
|
||||
vendor: OpenShift
|
||||
name: home
|
||||
spec:
|
||||
hubAcceptsClient: true
|
||||
leaseDurationSeconds: 60
|
||||
managedClusterClientConfigs:
|
||||
- url: https://api.home.ocplab.com:6443
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: cluster.open-cluster-management.io/v1
|
||||
kind: ManagedCluster
|
||||
metadata:
|
||||
annotations:
|
||||
open-cluster-management/created-via: other
|
||||
labels:
|
||||
cloud: Other
|
||||
cluster.open-cluster-management.io/clusterset: default
|
||||
gitops: local.hub
|
||||
color: "3E8635"
|
||||
local-cluster: "true"
|
||||
name: local-cluster
|
||||
velero.io/exclude-from-backup: "true"
|
||||
vendor: OpenShift
|
||||
name: local-cluster
|
||||
spec:
|
||||
hubAcceptsClient: true
|
||||
leaseDurationSeconds: 60
|
||||
managedClusterClientConfigs:
|
||||
- url: https://api.hub.ocplab.com:6443
|
||||
@@ -0,0 +1,2 @@
|
||||
resources:
|
||||
- policy-cert-expiration.yaml
|
||||
@@ -0,0 +1,50 @@
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: certificate-expiration
|
||||
annotations:
|
||||
policy.open-cluster-management.io/categories: SC System and Communications Protection
|
||||
policy.open-cluster-management.io/standards: NIST SP 800-53
|
||||
policy.open-cluster-management.io/controls: SC-8 Transmission Confidentiality and Integrity
|
||||
spec:
|
||||
disabled: false
|
||||
remediationAction: inform
|
||||
policy-templates:
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: CertificatePolicy
|
||||
metadata:
|
||||
name: policy-certificate
|
||||
spec:
|
||||
namespaceSelector:
|
||||
include:
|
||||
- default
|
||||
exclude:
|
||||
- kube-*
|
||||
remediationAction: inform
|
||||
severity: low
|
||||
minimumDuration: 300h
|
||||
---
|
||||
apiVersion: apps.open-cluster-management.io/v1
|
||||
kind: PlacementRule
|
||||
metadata:
|
||||
name: certificate-expiration-placement
|
||||
spec:
|
||||
clusterSelector:
|
||||
matchExpressions: []
|
||||
clusterConditions:
|
||||
- status: "True"
|
||||
type: ManagedClusterConditionAvailable
|
||||
---
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PlacementBinding
|
||||
metadata:
|
||||
name: certificate-expiration-placement
|
||||
placementRef:
|
||||
name: certificate-expiration-placement
|
||||
apiGroup: apps.open-cluster-management.io
|
||||
kind: PlacementRule
|
||||
subjects:
|
||||
- name: certificate-expiration
|
||||
apiGroup: policy.open-cluster-management.io
|
||||
kind: Policy
|
||||
@@ -0,0 +1,2 @@
|
||||
resources:
|
||||
- scan-nist-800-53-policy.yaml
|
||||
@@ -0,0 +1,55 @@
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: scan-nist-800-53
|
||||
annotations:
|
||||
policy.open-cluster-management.io/standards: NIST-CSF
|
||||
policy.open-cluster-management.io/categories: PR.IP Information Protection Processes and Procedures
|
||||
policy.open-cluster-management.io/controls: PR.IP-1 Baseline Configuration
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
disabled: false
|
||||
policy-templates:
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: scan-nist-800-53
|
||||
spec:
|
||||
remediationAction: inform
|
||||
severity: high
|
||||
object-templates:
|
||||
- complianceType: mustnothave
|
||||
objectDefinition:
|
||||
apiVersion: compliance.openshift.io/v1alpha1
|
||||
kind: ComplianceCheckResult
|
||||
metadata:
|
||||
namespace: openshift-compliance
|
||||
labels:
|
||||
compliance.openshift.io/check-status: FAIL
|
||||
compliance.openshift.io/suite: cis-compliance
|
||||
---
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PlacementBinding
|
||||
metadata:
|
||||
name: binding-scan-nist-800-53
|
||||
placementRef:
|
||||
name: placement-scan-nist-800-53
|
||||
kind: PlacementRule
|
||||
apiGroup: apps.open-cluster-management.io
|
||||
subjects:
|
||||
- name: scan-nist-800-53
|
||||
kind: Policy
|
||||
apiGroup: policy.open-cluster-management.io
|
||||
---
|
||||
apiVersion: apps.open-cluster-management.io/v1
|
||||
kind: PlacementRule
|
||||
metadata:
|
||||
name: placement-scan-nist-800-53
|
||||
spec:
|
||||
clusterConditions:
|
||||
- status: 'True'
|
||||
type: ManagedClusterConditionAvailable
|
||||
clusterSelector:
|
||||
matchExpressions:
|
||||
- {key: vendor, operator: In, values: ["OpenShift"]}
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
annotations:
|
||||
openshift.io/description: ACM Configuration Policies
|
||||
openshift.io/display-name: ACM Configuration Policies
|
||||
name: acm-config-policies
|
||||
@@ -0,0 +1,131 @@
|
||||
# Sample policy to configure gatekeeper to exclude namespaces from certain processes for all constraints in the cluster
|
||||
# See: https://github.com/open-policy-agent/gatekeeper/tree/release-3.3#exempting-namespaces-from-gatekeeper
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: policy-gatekeeper-config-exclude-namespaces
|
||||
annotations:
|
||||
policy.open-cluster-management.io/standards: NIST SP 800-53
|
||||
policy.open-cluster-management.io/categories: CM Configuration Management
|
||||
policy.open-cluster-management.io/controls: CM-2 Baseline Configuration
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
disabled: false
|
||||
policy-templates:
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: policy-gatekeeper-config-exclude-namespaces
|
||||
spec:
|
||||
remediationAction: enforce # will be overridden by remediationAction in parent policy
|
||||
severity: low
|
||||
object-templates:
|
||||
- complianceType: mustonlyhave
|
||||
objectDefinition:
|
||||
apiVersion: config.gatekeeper.sh/v1alpha1
|
||||
kind: Config
|
||||
metadata:
|
||||
name: config
|
||||
namespace: openshift-gatekeeper-system
|
||||
spec:
|
||||
match:
|
||||
- excludedNamespaces:
|
||||
- hive
|
||||
- kube-node-lease
|
||||
- kube-public
|
||||
- kube-storage-version-migrator-operator
|
||||
- kube-system
|
||||
- open-cluster-management
|
||||
- open-cluster-management-hub
|
||||
- open-cluster-management-agent
|
||||
- open-cluster-management-agent-addon
|
||||
- openshift
|
||||
- openshift-apiserver
|
||||
- openshift-apiserver-operator
|
||||
- openshift-authentication
|
||||
- openshift-authentication-operator
|
||||
- openshift-cloud-credential-operator
|
||||
- openshift-cluster-csi-drivers
|
||||
- openshift-cluster-machine-approver
|
||||
- openshift-cluster-node-tuning-operator
|
||||
- openshift-cluster-samples-operator
|
||||
- openshift-cluster-storage-operator
|
||||
- openshift-cluster-version
|
||||
- openshift-compliance
|
||||
- openshift-config
|
||||
- openshift-config-managed
|
||||
- openshift-config-operator
|
||||
- openshift-console
|
||||
- openshift-console-operator
|
||||
- openshift-console-user-settings
|
||||
- openshift-controller-manager
|
||||
- openshift-controller-manager-operator
|
||||
- openshift-dns
|
||||
- openshift-dns-operator
|
||||
- openshift-etcd
|
||||
- openshift-etcd-operator
|
||||
- openshift-gatekeeper-operator
|
||||
- openshift-gatekeeper-system
|
||||
- openshift-image-registry
|
||||
- openshift-infra
|
||||
- openshift-ingress
|
||||
- openshift-ingress-canary
|
||||
- openshift-ingress-operator
|
||||
- openshift-insights
|
||||
- openshift-kni-infra
|
||||
- openshift-kube-apiserver
|
||||
- openshift-kube-apiserver-operator
|
||||
- openshift-kube-controller-manager
|
||||
- openshift-kube-controller-manager-operator
|
||||
- openshift-kube-scheduler
|
||||
- openshift-kube-scheduler-operator
|
||||
- openshift-kube-storage-version-migrator
|
||||
- openshift-kube-storage-version-migrator-operator
|
||||
- openshift-kubevirt-infra
|
||||
- openshift-machine-api
|
||||
- openshift-machine-config-operator
|
||||
- openshift-marketplace
|
||||
- openshift-monitoring
|
||||
- openshift-multus
|
||||
- openshift-network-diagnostics
|
||||
- openshift-network-operator
|
||||
- openshift-node
|
||||
- openshift-oauth-apiserver
|
||||
- openshift-openstack-infra
|
||||
- openshift-operators
|
||||
- openshift-operator-lifecycle-manager
|
||||
- openshift-ovirt-infra
|
||||
- openshift-ovn-kubernetes
|
||||
- openshift-sdn
|
||||
- openshift-service-ca
|
||||
- openshift-service-ca-operator
|
||||
- openshift-user-workload-monitoring
|
||||
- openshift-vsphere-infra
|
||||
processes:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PlacementBinding
|
||||
metadata:
|
||||
name: binding-policy-gatekeeper-config-exclude-namespaces
|
||||
placementRef:
|
||||
name: placement-policy-gatekeeper-config-exclude-namespaces
|
||||
kind: PlacementRule
|
||||
apiGroup: apps.open-cluster-management.io
|
||||
subjects:
|
||||
- name: policy-gatekeeper-config-exclude-namespaces
|
||||
kind: Policy
|
||||
apiGroup: policy.open-cluster-management.io
|
||||
---
|
||||
apiVersion: apps.open-cluster-management.io/v1
|
||||
kind: PlacementRule
|
||||
metadata:
|
||||
name: placement-policy-gatekeeper-config-exclude-namespaces
|
||||
spec:
|
||||
clusterConditions:
|
||||
- status: "True"
|
||||
type: ManagedClusterConditionAvailable
|
||||
clusterSelector:
|
||||
matchExpressions:
|
||||
- {key: policy, operator: In, values: ["opa"]}
|
||||
@@ -0,0 +1,139 @@
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: policy-gatekeeper-operator
|
||||
annotations:
|
||||
policy.open-cluster-management.io/standards: NIST SP 800-53
|
||||
policy.open-cluster-management.io/categories: CM Configuration Management
|
||||
policy.open-cluster-management.io/controls: CM-2 Baseline Configuration
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
disabled: false
|
||||
policy-templates:
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: gatekeeper-operator-ns
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
severity: high
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: openshift-gatekeeper-operator
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: gatekeeper-operator-catalog-source
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
severity: high
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: CatalogSource
|
||||
metadata:
|
||||
name: gatekeeper-operator
|
||||
namespace: openshift-gatekeeper-operator
|
||||
spec:
|
||||
displayName: Gatekeeper Operator Upstream
|
||||
publisher: github.com/font/gatekeeper-operator
|
||||
sourceType: grpc
|
||||
image: 'quay.io/gatekeeper/gatekeeper-operator-bundle-index:v0.2.1'
|
||||
updateStrategy:
|
||||
registryPoll:
|
||||
interval: 45m
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: gatekeeper-operator-group
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
severity: high
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: operators.coreos.com/v1
|
||||
kind: OperatorGroup
|
||||
metadata:
|
||||
name: gatekeeper-operator
|
||||
namespace: openshift-gatekeeper-operator
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: gatekeeper-operator-subscription
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
severity: high
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: Subscription
|
||||
metadata:
|
||||
name: gatekeeper-operator-sub
|
||||
namespace: openshift-gatekeeper-operator
|
||||
spec:
|
||||
channel: stable
|
||||
name: gatekeeper-operator
|
||||
source: gatekeeper-operator
|
||||
sourceNamespace: openshift-gatekeeper-operator
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: gatekeeper
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
severity: high
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: operator.gatekeeper.sh/v1alpha1
|
||||
kind: Gatekeeper
|
||||
metadata:
|
||||
name: gatekeeper
|
||||
spec:
|
||||
audit:
|
||||
auditChunkSize: 500
|
||||
logLevel: INFO
|
||||
replicas: 1
|
||||
validatingWebhook: Enabled
|
||||
mutatingWebhook: Disabled
|
||||
webhook:
|
||||
emitAdmissionEvents: Enabled
|
||||
logLevel: INFO
|
||||
replicas: 2
|
||||
---
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PlacementBinding
|
||||
metadata:
|
||||
name: binding-policy-gatekeeper-operator
|
||||
placementRef:
|
||||
name: placement-policy-gatekeeper-operator
|
||||
kind: PlacementRule
|
||||
apiGroup: apps.open-cluster-management.io
|
||||
subjects:
|
||||
- name: policy-gatekeeper-operator
|
||||
kind: Policy
|
||||
apiGroup: policy.open-cluster-management.io
|
||||
---
|
||||
apiVersion: apps.open-cluster-management.io/v1
|
||||
kind: PlacementRule
|
||||
metadata:
|
||||
name: placement-policy-gatekeeper-operator
|
||||
spec:
|
||||
clusterConditions:
|
||||
- status: "True"
|
||||
type: ManagedClusterConditionAvailable
|
||||
clusterSelector:
|
||||
matchExpressions:
|
||||
- {key: policy, operator: In, values: ["opa"]}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace: acm-policies
|
||||
|
||||
resources:
|
||||
- placement.yaml
|
||||
- managedclustersetbinding.yaml
|
||||
|
||||
generators:
|
||||
- policy-generator-config.yaml
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: cluster.open-cluster-management.io/v1beta2
|
||||
kind: ManagedClusterSetBinding
|
||||
metadata:
|
||||
name: global
|
||||
namespace: acm-policies
|
||||
spec:
|
||||
clusterSet: global
|
||||
@@ -0,0 +1,39 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: eso-token-cluster
|
||||
namespace: external-secrets
|
||||
data:
|
||||
dopplerToken: '{{hub (fromSecret "acm-policies" (printf "eso-token-cluster-%s" .ManagedClusterName) "dopplerToken") hub}}'
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ClusterSecretStore
|
||||
metadata:
|
||||
name: doppler-cluster
|
||||
spec:
|
||||
provider:
|
||||
doppler:
|
||||
auth:
|
||||
secretRef:
|
||||
dopplerToken:
|
||||
name: eso-token-cluster
|
||||
key: dopplerToken
|
||||
namespace: external-secrets
|
||||
|
||||
conditions:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
openshift.io/cluster-monitoring: "true"
|
||||
|
||||
- namespaces:
|
||||
- "cert-manager"
|
||||
- "dev-tools"
|
||||
- "gitops"
|
||||
- "openshift-config"
|
||||
- "openshift-gitops"
|
||||
- "openshift-monitoring"
|
||||
- "openshift-pipelines"
|
||||
- "stackrox"
|
||||
- "stackrox-secured-cluster-service"
|
||||
- "tenant-secrets"
|
||||
- "trusted-profile-analyzer"
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace: openshift-gitops
|
||||
|
||||
resources:
|
||||
- prometheus-rules.yaml
|
||||
@@ -0,0 +1,31 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: PrometheusRule
|
||||
metadata:
|
||||
name: argocd-health-alerts
|
||||
annotations:
|
||||
policy.open-cluster-management.io/disable-templates: "true"
|
||||
spec:
|
||||
groups:
|
||||
- name: ArgoCD
|
||||
rules:
|
||||
- alert: ArgoCDHealthAlert
|
||||
annotations:
|
||||
message: ArgoCD application {{ $labels.name }} is not healthy
|
||||
expr: argocd_app_info{namespace="openshift-gitops", health_status!~"Healthy|Suspended|Progressing|Degraded"} > 0
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
- alert: ArgoCDDegradedAlert
|
||||
annotations:
|
||||
message: ArgoCD application {{ $labels.name }} is degraded
|
||||
expr: argocd_app_info{namespace="openshift-gitops", health_status="Degraded"} > 0
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
- alert: ArgoCDStuckAlert
|
||||
annotations:
|
||||
message: ArgoCD application {{ $labels.name }} is stuck in progressing for more than 10m
|
||||
expr: argocd_app_info{namespace="openshift-gitops", health_status="Progressing"} > 0
|
||||
for: 10m
|
||||
labels:
|
||||
severity: warning
|
||||
@@ -0,0 +1,27 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: cluster-config-bootstrap
|
||||
namespace: openshift-gitops
|
||||
labels:
|
||||
gitops.ownedBy: cluster-config
|
||||
spec:
|
||||
destination:
|
||||
namespace: openshift-gitops
|
||||
server: https://kubernetes.default.svc
|
||||
project: bootstrap
|
||||
source:
|
||||
path: bootstrap/overlays/{{ fromClusterClaim "gitops" }}
|
||||
repoURL: https://github.com/gnunn-gitops/cluster-config-pins.git
|
||||
targetRevision: 'HEAD'
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: false
|
||||
selfHeal: false
|
||||
ignoreDifferences:
|
||||
- group: argoproj.io
|
||||
kind: Application
|
||||
managedFieldsManagers:
|
||||
- argocd-server
|
||||
jsonPointers:
|
||||
- /spec/syncPolicy/automated
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AppProject
|
||||
metadata:
|
||||
name: bootstrap
|
||||
namespace: openshift-gitops
|
||||
spec:
|
||||
clusterResourceWhitelist:
|
||||
- group: '*'
|
||||
kind: '*'
|
||||
description: Project for bootstrap cluster app
|
||||
destinations:
|
||||
- namespace: '*'
|
||||
server: https://kubernetes.default.svc
|
||||
sourceRepos:
|
||||
- https://github.com/gnunn-gitops/cluster-config
|
||||
- https://github.com/gnunn-gitops/cluster-config-pins
|
||||
@@ -0,0 +1,3 @@
|
||||
resources:
|
||||
- bootstrap-appproject.yaml
|
||||
- bootstrap-app.yaml
|
||||
@@ -0,0 +1,389 @@
|
||||
apiVersion: argoproj.io/v1beta1
|
||||
kind: ArgoCD
|
||||
metadata:
|
||||
name: openshift-gitops
|
||||
namespace: openshift-gitops
|
||||
spec:
|
||||
resourceTrackingMethod: annotation
|
||||
applicationSet: {}
|
||||
extraConfig:
|
||||
exec.enabled: "true"
|
||||
resource.respectRBAC: "normal"
|
||||
resource.ignoreResourceUpdatesEnabled: 'true'
|
||||
resource.compareoptions: |
|
||||
ignoreAggregatedRoles: true
|
||||
resource.customizations.ignoreResourceUpdates.external-secrets.io_ExternalSecret: |
|
||||
jsonPointers:
|
||||
- /status/refreshTime
|
||||
resource.customizations.ignoreResourceUpdates.ocs.openshift.io_StorageCluster: |
|
||||
jsonPointers:
|
||||
- /status
|
||||
- /metadata/resourceVersion
|
||||
resource.customizations.ignoreResourceUpdates.ocs.openshift.io_StorageSystem: |
|
||||
jsonPointers:
|
||||
- /status
|
||||
- /metadata/resourceVersion
|
||||
resource.customizations.ignoreResourceUpdates.noobaa.io_Noobaa: |
|
||||
jsonPointers:
|
||||
- /status
|
||||
- /metadata/resourceVersion
|
||||
resource.customizations.ignoreResourceUpdates.noobaa.io_BackingStore: |
|
||||
jsonPointers:
|
||||
- /status
|
||||
- /metadata/resourceVersion
|
||||
accounts.admin: apiKey, login
|
||||
ui.cssurl: 'https://gnunn-gitops.github.io/cluster-config/themes/{{ fromClusterClaim "gitops" }}/custom-cluster.css'
|
||||
kustomizeBuildOptions: "--enable-helm --enable-alpha-plugins"
|
||||
oidcConfig: |
|
||||
name: Keycloak
|
||||
issuer: https://sso.ocplab.com/realms/ocplab
|
||||
clientID: argocd
|
||||
clientSecret: $oidc.keycloak.clientSecret
|
||||
requestedScopes: ["openid", "profile", "email", "groups"]
|
||||
controller:
|
||||
extraCommandArgs:
|
||||
- '--persist-resource-health=false'
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 1000m
|
||||
memory: 3Gi
|
||||
monitoring:
|
||||
enabled: true
|
||||
repo:
|
||||
sidecarContainers:
|
||||
- name: setenv-cmp-plugin
|
||||
command: [/var/run/argocd/argocd-cmp-server]
|
||||
env:
|
||||
- name: KUSTOMIZE_PLUGIN_HOME
|
||||
value: /etc/kustomize/plugin
|
||||
- name: INFRASTRUCTURE_ID
|
||||
value: '{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").status.infrastructureName }}'
|
||||
- name: CLUSTER_ID
|
||||
value: '{{ (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").spec.clusterID }}'
|
||||
- name: CLUSTER_GITOPS_NAME
|
||||
value: '{{ fromClusterClaim "gitops" }}'
|
||||
- name: CLUSTER_NAME
|
||||
value: '{{ fromClusterClaim "name" }}'
|
||||
- name: SUB_DOMAIN
|
||||
value: '{{ (lookup "config.openshift.io/v1" "Ingress" "openshift-ingress" "cluster").spec.domain }}'
|
||||
- name: BASE_DOMAIN
|
||||
value: '{{ (lookup "config.openshift.io/v1" "DNS" "" "cluster").spec.baseDomain }}'
|
||||
- name: COLOR
|
||||
value: '{{ default "0066CC" (fromClusterClaim "color") }}'
|
||||
image: quay.io/gnunn/tools:latest
|
||||
imagePullPolicy: Always
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
volumeMounts:
|
||||
- mountPath: /var/run/argocd
|
||||
name: var-files
|
||||
- mountPath: /home/argocd/cmp-server/plugins
|
||||
name: plugins
|
||||
- mountPath: /tmp
|
||||
name: tmp
|
||||
- mountPath: /home/argocd/cmp-server/config/plugin.yaml
|
||||
subPath: plugin.yaml
|
||||
name: setenv-cmp-plugin
|
||||
volumes:
|
||||
- configMap:
|
||||
name: setenv-cmp-plugin
|
||||
name: setenv-cmp-plugin
|
||||
resources:
|
||||
limits:
|
||||
cpu: '1'
|
||||
memory: 1.5Gi
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 768Mi
|
||||
redis:
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
server:
|
||||
insecure: true
|
||||
# host: 'openshift-gitops-server-openshift-gitops.{{ (lookup "config.openshift.io/v1" "Ingress" "openshift-ingress" "cluster").spec.domain }}'
|
||||
route:
|
||||
enabled: true
|
||||
tls:
|
||||
termination: edge
|
||||
insecureEdgeTerminationPolicy: Redirect
|
||||
notifications:
|
||||
enabled: true
|
||||
resourceActions:
|
||||
- group: compliance.openshift.io
|
||||
kind: ComplianceScan
|
||||
action: |
|
||||
discovery.lua: |
|
||||
local actions = {}
|
||||
local enabled = false
|
||||
if obj.status ~= nil and obj.status.phase == "DONE" then
|
||||
enabled = true
|
||||
end
|
||||
actions["rescan"] = {["disabled"] = not(enabled)}
|
||||
return actions
|
||||
definitions:
|
||||
- name: rescan
|
||||
action.lua: |
|
||||
if obj.metadata.annotations == nil then
|
||||
obj.metadata.annotations = {}
|
||||
end
|
||||
obj.metadata.annotations["compliance.openshift.io/rescan"] = ""
|
||||
return obj
|
||||
resourceHealthChecks:
|
||||
- group: argoproj.io
|
||||
kind: Application
|
||||
check: |
|
||||
hs = {}
|
||||
hs.status = "Progressing"
|
||||
hs.message = ""
|
||||
if obj.status ~= nil then
|
||||
if obj.status.health ~= nil then
|
||||
hs.status = obj.status.health.status
|
||||
hs.message = obj.status.health.message
|
||||
end
|
||||
end
|
||||
return hs
|
||||
- group: argoproj.io
|
||||
kind: RolloutManager
|
||||
check: |
|
||||
hs = {}
|
||||
if obj.status ~= nil then
|
||||
if obj.status.conditions ~= nil then
|
||||
for _, condition in ipairs(obj.status.conditions) do
|
||||
hs.message = condition.message
|
||||
break
|
||||
end
|
||||
end
|
||||
if obj.status.phase ~= nil then
|
||||
if obj.status.phase == "Failure" then
|
||||
hs.status = "Degraded"
|
||||
return hs
|
||||
elseif obj.status.phase == "Available" then
|
||||
hs.status = "Healthy"
|
||||
return hs
|
||||
elseif obj.status.phase == "Pending" then
|
||||
hs.status = "Progressing"
|
||||
return hs
|
||||
end
|
||||
end
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for operator to update status"
|
||||
return hs
|
||||
end
|
||||
- group: operators.coreos.com
|
||||
kind: Subscription
|
||||
check: |
|
||||
health_status = {}
|
||||
if obj.status ~= nil then
|
||||
if obj.status.conditions ~= nil then
|
||||
numDegraded = 0
|
||||
numPending = 0
|
||||
numSuspended = 0
|
||||
msg = ""
|
||||
for i, condition in pairs(obj.status.conditions) do
|
||||
msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. " | " .. (condition.reason and condition.reason or '') .. "\n"
|
||||
if condition.type == "InstallPlanPending" and condition.status == "True" then
|
||||
if condition.reason == "RequiresApproval" then
|
||||
numSuspended = numSuspended + 1
|
||||
else
|
||||
numPending = numPending + 1
|
||||
end
|
||||
elseif (condition.type == "InstallPlanMissing" and condition.reason ~= "ReferencedInstallPlanNotFound") then
|
||||
numDegraded = numDegraded + 1
|
||||
elseif (condition.type == "CatalogSourcesUnhealthy" or condition.type == "InstallPlanFailed") and condition.status == "True" then
|
||||
numDegraded = numDegraded + 1
|
||||
elseif (condition.type == "ResolutionFailed" and condition.reason ~= "ConstraintsNotSatisfiable") then
|
||||
numDegraded = numDegraded + 1
|
||||
elseif (condition.type == 'ChannelDeprecated' and condition.status == "True") then
|
||||
numDegraded = numDegraded + 1
|
||||
end
|
||||
end
|
||||
if numDegraded > 0 then
|
||||
health_status.status = "Degraded"
|
||||
health_status.message = msg
|
||||
return health_status
|
||||
elseif numSuspended > 0 then
|
||||
health_status.status = "Suspended"
|
||||
health_status.message = msg
|
||||
return health_status
|
||||
elseif numPending > 0 then
|
||||
health_status.status = "Progressing"
|
||||
health_status.message = "An install plan for a subscription is pending installation"
|
||||
return health_status
|
||||
else
|
||||
health_status.status = "Healthy"
|
||||
health_status.message = msg
|
||||
return health_status
|
||||
end
|
||||
end
|
||||
end
|
||||
health_status.status = "Progressing"
|
||||
health_status.message = "An install plan for a subscription is pending installation"
|
||||
return health_status
|
||||
- group: operators.coreos.com
|
||||
kind: InstallPlan
|
||||
check: |
|
||||
hs = {}
|
||||
if obj.status ~= nil then
|
||||
if obj.status.phase ~= nil then
|
||||
if obj.status.phase == "Complete" then
|
||||
hs.status = "Healthy"
|
||||
hs.message = obj.status.phase
|
||||
return hs
|
||||
elseif obj.status.phase == "RequiresApproval" then
|
||||
hs.status = "Suspended"
|
||||
hs.message = obj.status.phase
|
||||
return hs
|
||||
else
|
||||
hs.status = "Progressing"
|
||||
hs.message = obj.status.phase
|
||||
return hs
|
||||
end
|
||||
end
|
||||
end
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for InstallPlan to complete"
|
||||
return hs
|
||||
- group: platform.stackrox.io
|
||||
kind: Central
|
||||
check: |
|
||||
hs = {}
|
||||
if obj.status ~= nil and obj.status.conditions ~= nil then
|
||||
for i, condition in ipairs(obj.status.conditions) do
|
||||
if condition.status == "True" or condition.reason == "InstallSuccessful" or condition.reason == "UpgradeSuccessful" then
|
||||
hs.status = "Healthy"
|
||||
hs.message = "Install Successful"
|
||||
return hs
|
||||
end
|
||||
end
|
||||
end
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for Central to deploy."
|
||||
return hs
|
||||
- group: image.openshift.io
|
||||
kind: ImageStream
|
||||
check: |
|
||||
hs = {}
|
||||
hs.status = "Progressing"
|
||||
hs.message = ""
|
||||
if obj.status ~= nil then
|
||||
if obj.status.tags ~= nil then
|
||||
numTags = 0
|
||||
for _ , item in pairs(obj.status.tags) do
|
||||
numTags = numTags + 1
|
||||
numItems = 0
|
||||
if item.tags ~= nil then
|
||||
for _ , item in pairs(item.tags) do
|
||||
numItems = numItems + 1
|
||||
end
|
||||
if numItems == 0 then
|
||||
return hs
|
||||
end
|
||||
end
|
||||
end
|
||||
if numTags > 0 then
|
||||
hs.status = "Healthy"
|
||||
hs.message = "ImageStream has tags resolved"
|
||||
return hs
|
||||
end
|
||||
end
|
||||
end
|
||||
return hs
|
||||
- group: build.openshift.io
|
||||
kind: Build
|
||||
check: |
|
||||
hs = {}
|
||||
if obj.status ~= nil then
|
||||
if obj.status.phase ~= nil then
|
||||
if obj.status.phase == "Complete" then
|
||||
hs.status = "Healthy"
|
||||
hs.message = obj.status.phase
|
||||
return hs
|
||||
end
|
||||
end
|
||||
end
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for Build to complete"
|
||||
return hs
|
||||
- kind: PersistentVolumeClaim
|
||||
check: |
|
||||
hs = {}
|
||||
if obj.status ~= nil then
|
||||
if obj.status.phase ~= nil then
|
||||
if obj.status.phase == "Pending" then
|
||||
hs.status = "Healthy"
|
||||
hs.message = obj.status.phase
|
||||
return hs
|
||||
end
|
||||
if obj.status.phase == "Bound" then
|
||||
hs.status = "Healthy"
|
||||
hs.message = obj.status.phase
|
||||
return hs
|
||||
end
|
||||
end
|
||||
end
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for PVC"
|
||||
return hs
|
||||
resourceIgnoreDifferences:
|
||||
resourceIdentifiers:
|
||||
- group: route.openshift.io
|
||||
kind: Route
|
||||
customization:
|
||||
jsonPointers:
|
||||
- /status/ingress
|
||||
- /metadata/annotations
|
||||
- group: quay.redhat.com
|
||||
kind: QuayRegistry
|
||||
customization:
|
||||
jsonPointers:
|
||||
- /status/ingress
|
||||
- group: cluster.open-cluster-management.io
|
||||
kind: ManagedCluster
|
||||
customization:
|
||||
jsonPointers:
|
||||
- /spec/managedClusterClientConfigs
|
||||
resourceExclusions: |
|
||||
- apiGroups:
|
||||
- tekton.dev
|
||||
clusters:
|
||||
- '*'
|
||||
kinds:
|
||||
- TaskRun
|
||||
- PipelineRun
|
||||
- apiGroups:
|
||||
- operator.tekton.dev
|
||||
clusters:
|
||||
- '*'
|
||||
kinds:
|
||||
- TektonAddon
|
||||
- TektonInstallerSet
|
||||
- apiGroups:
|
||||
- compliance.openshift.io
|
||||
kinds:
|
||||
- ComplianceCheckResult
|
||||
- ComplianceRemediation
|
||||
- apiGroups:
|
||||
- policy.open-cluster-management.io
|
||||
kinds:
|
||||
- ConfigurationPolicy
|
||||
- apiGroups:
|
||||
- noobaa.io
|
||||
kinds:
|
||||
- NooBaa
|
||||
- BucketClass
|
||||
ha:
|
||||
enabled: false
|
||||
rbac:
|
||||
defaultPolicy: 'role:none'
|
||||
policy: |
|
||||
p, role:none, *, *, */*, deny
|
||||
g, system:cluster-admins, role:admin
|
||||
g, cluster-admins, role:admin
|
||||
scopes: "[groups]"
|
||||
@@ -0,0 +1,3 @@
|
||||
resources:
|
||||
- setenv-cmp-plugin-cm.yaml
|
||||
- argocd.yaml
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: setenv-cmp-plugin
|
||||
namespace: openshift-gitops
|
||||
data:
|
||||
plugin.yaml: |
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ConfigManagementPlugin
|
||||
metadata:
|
||||
name: setenv-cmp-plugin
|
||||
spec:
|
||||
init:
|
||||
command: [sh, -c, 'echo "Initializing setenv-plugin-cmp..."']
|
||||
generate:
|
||||
command:
|
||||
- sh
|
||||
- "-c"
|
||||
- "set -o pipefail && kustomize build --enable-helm --enable-alpha-plugins . | envsub"
|
||||
@@ -0,0 +1,2 @@
|
||||
resources:
|
||||
- notifications-config.yaml
|
||||
@@ -0,0 +1,256 @@
|
||||
# No longer needed with NotificationsConfig introduced in 1.12
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: openshift-gitops
|
||||
app.kubernetes.io/name: argocd-notifications-cm
|
||||
app.kubernetes.io/part-of: argocd
|
||||
annotation:
|
||||
policy.open-cluster-management.io/disable-templates: "true"
|
||||
name: argocd-notifications-cm
|
||||
namespace: openshift-gitops
|
||||
data:
|
||||
service.slack: |
|
||||
token: $slack-token
|
||||
template.app-deployed: |-
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#18be52",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Revision",
|
||||
"value": "{{.app.status.sync.revision}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
template.app-health-degraded: |-
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#f4c030",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Health Status",
|
||||
"value": "{{.app.status.health.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
template.app-sync-failed: |-
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#E96D76",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
template.app-sync-running: |-
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#0DADEA",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
template.app-sync-status-unknown: |-
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#E96D76",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
template.app-sync-succeeded: |-
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#18be52",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
# trigger.on-created: |-
|
||||
# - description: Application is created.
|
||||
# oncePer: app.metadata.name
|
||||
# send:
|
||||
# - app-created
|
||||
# when: "true"
|
||||
# trigger.on-deleted: |-
|
||||
# - description: Application is deleted.
|
||||
# oncePer: app.metadata.name
|
||||
# send:
|
||||
# - app-deleted
|
||||
# when: app.metadata.deletionTimestamp != nil
|
||||
trigger.on-deployed: |-
|
||||
- description: Application is synced and healthy. Triggered once per commit.
|
||||
oncePer: app.status.operationState.syncResult.revision
|
||||
send:
|
||||
- app-deployed
|
||||
when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status
|
||||
== 'Healthy'
|
||||
trigger.on-health-degraded: |-
|
||||
- description: Application has degraded
|
||||
send:
|
||||
- app-health-degraded
|
||||
when: app.status.health.status == 'Degraded'
|
||||
trigger.on-sync-failed: |-
|
||||
- description: Application syncing has failed
|
||||
send:
|
||||
- app-sync-failed
|
||||
when: app.status.operationState.phase in ['Error', 'Failed']
|
||||
trigger.on-sync-running: |-
|
||||
- description: Application is being synced
|
||||
send:
|
||||
- app-sync-running
|
||||
when: app.status.operationState.phase in ['Running']
|
||||
trigger.on-sync-status-unknown: |-
|
||||
- description: Application status is 'Unknown'
|
||||
end:
|
||||
- app-sync-status-unknown
|
||||
when: app.status.sync.status == 'Unknown'
|
||||
trigger.on-sync-succeeded: |-
|
||||
- description: Application syncing has succeeded
|
||||
send:
|
||||
- app-sync-succeeded
|
||||
when: app.status.operationState.phase in ['Succeeded']
|
||||
@@ -0,0 +1,540 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: NotificationsConfiguration
|
||||
metadata:
|
||||
name: default-notifications-configuration
|
||||
namespace: openshift-gitops
|
||||
spec:
|
||||
services:
|
||||
service.slack: |
|
||||
token: $slack-token
|
||||
templates:
|
||||
template.app-created: |-
|
||||
email:
|
||||
subject: Application {{.app.metadata.name}} has been created.
|
||||
message: Application {{.app.metadata.name}} has been created.
|
||||
teams:
|
||||
title: Application {{.app.metadata.name}} has been created.
|
||||
template.app-deleted: |-
|
||||
email:
|
||||
subject: Application {{.app.metadata.name}} has been deleted.
|
||||
message: Application {{.app.metadata.name}} has been deleted.
|
||||
teams:
|
||||
title: Application {{.app.metadata.name}} has been deleted.
|
||||
template.app-deployed: |-
|
||||
email:
|
||||
subject: New version of an application {{.app.metadata.name}} is up and running.
|
||||
message: |
|
||||
{{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} is now running new version of deployments manifests.
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#18be52",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Revision",
|
||||
"value": "{{.app.status.sync.revision}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
teams:
|
||||
facts: |
|
||||
[{
|
||||
"name": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}"
|
||||
},
|
||||
{
|
||||
"name": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}"
|
||||
},
|
||||
{
|
||||
"name": "Revision",
|
||||
"value": "{{.app.status.sync.revision}}"
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"name": "{{$c.type}}",
|
||||
"value": "{{$c.message}}"
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
potentialAction: |-
|
||||
[{
|
||||
"@type":"OpenUri",
|
||||
"name":"Operation Application",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Repository",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
|
||||
}]
|
||||
}]
|
||||
themeColor: '#000080'
|
||||
title: New version of an application {{.app.metadata.name}} is up and running.
|
||||
template.app-health-degraded: |-
|
||||
email:
|
||||
subject: Application {{.app.metadata.name}} has degraded.
|
||||
message: |
|
||||
{{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} has degraded.
|
||||
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#f4c030",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Health Status",
|
||||
"value": "{{.app.status.health.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
teams:
|
||||
facts: |
|
||||
[{
|
||||
"name": "Health Status",
|
||||
"value": "{{.app.status.health.status}}"
|
||||
},
|
||||
{
|
||||
"name": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}"
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"name": "{{$c.type}}",
|
||||
"value": "{{$c.message}}"
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
potentialAction: |
|
||||
[{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Application",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Repository",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
|
||||
}]
|
||||
}]
|
||||
themeColor: '#FF0000'
|
||||
title: Application {{.app.metadata.name}} has degraded.
|
||||
template.app-sync-failed: |-
|
||||
email:
|
||||
subject: Failed to sync application {{.app.metadata.name}}.
|
||||
message: |
|
||||
{{if eq .serviceType "slack"}}:exclamation:{{end}} The sync operation of application {{.app.metadata.name}} has failed at {{.app.status.operationState.finishedAt}} with the following error: {{.app.status.operationState.message}}
|
||||
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#E96D76",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
teams:
|
||||
facts: |
|
||||
[{
|
||||
"name": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}"
|
||||
},
|
||||
{
|
||||
"name": "Failed at",
|
||||
"value": "{{.app.status.operationState.finishedAt}}"
|
||||
},
|
||||
{
|
||||
"name": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}"
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"name": "{{$c.type}}",
|
||||
"value": "{{$c.message}}"
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
potentialAction: |-
|
||||
[{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Operation",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Repository",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
|
||||
}]
|
||||
}]
|
||||
themeColor: '#FF0000'
|
||||
title: Failed to sync application {{.app.metadata.name}}.
|
||||
template.app-sync-running: |-
|
||||
email:
|
||||
subject: Start syncing application {{.app.metadata.name}}.
|
||||
message: |
|
||||
The sync operation of application {{.app.metadata.name}} has started at {{.app.status.operationState.startedAt}}.
|
||||
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#0DADEA",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
teams:
|
||||
facts: |
|
||||
[{
|
||||
"name": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}"
|
||||
},
|
||||
{
|
||||
"name": "Started at",
|
||||
"value": "{{.app.status.operationState.startedAt}}"
|
||||
},
|
||||
{
|
||||
"name": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}"
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"name": "{{$c.type}}",
|
||||
"value": "{{$c.message}}"
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
potentialAction: |-
|
||||
[{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Operation",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Repository",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
|
||||
}]
|
||||
}]
|
||||
title: Start syncing application {{.app.metadata.name}}.
|
||||
template.app-sync-status-unknown: |-
|
||||
email:
|
||||
subject: Application {{.app.metadata.name}} sync status is 'Unknown'
|
||||
message: |
|
||||
{{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} sync is 'Unknown'.
|
||||
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
|
||||
{{if ne .serviceType "slack"}}
|
||||
{{range $c := .app.status.conditions}}
|
||||
* {{$c.message}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#E96D76",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
teams:
|
||||
facts: |
|
||||
[{
|
||||
"name": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}"
|
||||
},
|
||||
{
|
||||
"name": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}"
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"name": "{{$c.type}}",
|
||||
"value": "{{$c.message}}"
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
potentialAction: |-
|
||||
[{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Application",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Repository",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
|
||||
}]
|
||||
}]
|
||||
title: Application {{.app.metadata.name}} sync status is 'Unknown'
|
||||
template.app-sync-succeeded: |-
|
||||
email:
|
||||
subject: Application {{.app.metadata.name}} has been successfully synced.
|
||||
message: |
|
||||
{{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}.
|
||||
Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .
|
||||
slack:
|
||||
attachments: |
|
||||
[{
|
||||
"title": "{{ .app.metadata.name}}",
|
||||
"title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
|
||||
"color": "#18be52",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}",
|
||||
"short": true
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"title": "{{$c.type}}",
|
||||
"value": "{{$c.message}}",
|
||||
"short": true
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
}]
|
||||
deliveryPolicy: Post
|
||||
groupingKey: ""
|
||||
notifyBroadcast: false
|
||||
teams:
|
||||
facts: |
|
||||
[{
|
||||
"name": "Sync Status",
|
||||
"value": "{{.app.status.sync.status}}"
|
||||
},
|
||||
{
|
||||
"name": "Synced at",
|
||||
"value": "{{.app.status.operationState.finishedAt}}"
|
||||
},
|
||||
{
|
||||
"name": "Repository",
|
||||
"value": "{{.app.spec.source.repoURL}}"
|
||||
}
|
||||
{{range $index, $c := .app.status.conditions}}
|
||||
{{if not $index}},{{end}}
|
||||
{{if $index}},{{end}}
|
||||
{
|
||||
"name": "{{$c.type}}",
|
||||
"value": "{{$c.message}}"
|
||||
}
|
||||
{{end}}
|
||||
]
|
||||
potentialAction: |-
|
||||
[{
|
||||
"@type":"OpenUri",
|
||||
"name":"Operation Details",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"@type":"OpenUri",
|
||||
"name":"Open Repository",
|
||||
"targets":[{
|
||||
"os":"default",
|
||||
"uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}"
|
||||
}]
|
||||
}]
|
||||
themeColor: '#000080'
|
||||
title: Application {{.app.metadata.name}} has been successfully synced
|
||||
triggers:
|
||||
trigger.on-created: |-
|
||||
- description: Application is created.
|
||||
oncePer: app.metadata.name
|
||||
send:
|
||||
- app-created
|
||||
when: "true"
|
||||
trigger.on-deleted: |-
|
||||
- description: Application is deleted.
|
||||
oncePer: app.metadata.name
|
||||
send:
|
||||
- app-deleted
|
||||
when: app.metadata.deletionTimestamp != nil
|
||||
trigger.on-deployed: |-
|
||||
- description: Application is synced and healthy. Triggered once per commit.
|
||||
oncePer: app.status.operationState.syncResult.revision
|
||||
send:
|
||||
- app-deployed
|
||||
when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status
|
||||
== 'Healthy'
|
||||
trigger.on-health-degraded: |-
|
||||
- description: Application has degraded
|
||||
send:
|
||||
- app-health-degraded
|
||||
when: app.status.health.status == 'Degraded'
|
||||
trigger.on-sync-failed: |-
|
||||
- description: Application syncing has failed
|
||||
send:
|
||||
- app-sync-failed
|
||||
when: app.status.operationState.phase in ['Error', 'Failed']
|
||||
trigger.on-sync-running: |-
|
||||
- description: Application is being synced
|
||||
send:
|
||||
- app-sync-running
|
||||
when: app.status.operationState.phase in ['Running']
|
||||
trigger.on-sync-status-unknown: |-
|
||||
- description: Application status is 'Unknown'
|
||||
send:
|
||||
- app-sync-status-unknown
|
||||
when: app.status.sync.status == 'Unknown'
|
||||
trigger.on-sync-succeeded: |-
|
||||
- description: Application syncing has succeeded
|
||||
send:
|
||||
- app-sync-succeeded
|
||||
when: app.status.operationState.phase in ['Succeeded']
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: argocd-secret
|
||||
namespace: openshift-gitops
|
||||
spec:
|
||||
data:
|
||||
- remoteRef:
|
||||
conversionStrategy: Default
|
||||
decodingStrategy: None
|
||||
key: OIDC_ARGOCD
|
||||
secretKey: oidc.keycloak.clientSecret
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
kind: ClusterSecretStore
|
||||
name: doppler-cluster
|
||||
target:
|
||||
creationPolicy: Merge
|
||||
deletionPolicy: Retain
|
||||
name: argocd-secret
|
||||
@@ -0,0 +1,3 @@
|
||||
resources:
|
||||
- argocd-external-secret.yaml
|
||||
- notifications-secret.yaml
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: argocd-notifications-secret
|
||||
namespace: openshift-gitops
|
||||
spec:
|
||||
secretStoreRef:
|
||||
kind: ClusterSecretStore
|
||||
name: doppler-cluster
|
||||
target:
|
||||
name: argocd-notifications-secret
|
||||
creationPolicy: Merge
|
||||
deletionPolicy: Retain
|
||||
data:
|
||||
- secretKey: slack-token
|
||||
remoteRef:
|
||||
key: GITOPS_SLACK_TOKEN
|
||||
@@ -0,0 +1,12 @@
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: argocd-application-controller-cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: openshift-gitops-argocd-application-controller
|
||||
namespace: openshift-gitops
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
@@ -0,0 +1,39 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
name: gitops-controller
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
gitops/aggregate-to-controller: "true"
|
||||
rules: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: gitops-controller-admin
|
||||
labels:
|
||||
gitops/aggregate-to-controller: "true"
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
rules: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: gitops-controller-view
|
||||
labels:
|
||||
gitops/aggregate-to-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
@@ -0,0 +1,53 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: gitops-server
|
||||
rules:
|
||||
- verbs:
|
||||
- get
|
||||
- patch
|
||||
- delete
|
||||
apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
- verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
- verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- patch
|
||||
apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- applications
|
||||
- appprojects
|
||||
- applicationsets
|
||||
- verbs:
|
||||
- create
|
||||
- list
|
||||
apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- events
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods/exec
|
||||
verbs:
|
||||
- create
|
||||
@@ -0,0 +1,8 @@
|
||||
resources:
|
||||
- sub-namespace.yaml
|
||||
- sub-operatorgroup.yaml
|
||||
- subscription.yaml
|
||||
- namespace.yaml
|
||||
- gitops-controller-rbac.yaml
|
||||
- gitops-server-rbac.yaml
|
||||
- cluster-admin-rolebinding.yaml
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
openshift.io/cluster-monitoring: "true"
|
||||
name: openshift-gitops
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
openshift.io/cluster-monitoring: "true"
|
||||
name: openshift-gitops-operator
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: operators.coreos.com/v1
|
||||
kind: OperatorGroup
|
||||
metadata:
|
||||
name: gitops-operators
|
||||
namespace: openshift-gitops-operator
|
||||
spec:
|
||||
upgradeStrategy: Default
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: Subscription
|
||||
metadata:
|
||||
name: openshift-gitops-operator
|
||||
namespace: openshift-gitops-operator
|
||||
spec:
|
||||
config:
|
||||
env:
|
||||
- name: ARGOCD_CLUSTER_CONFIG_NAMESPACES
|
||||
value: openshift-gitops, gitops
|
||||
- name: CONTROLLER_CLUSTER_ROLE
|
||||
value: gitops-controller
|
||||
- name: SERVER_CLUSTER_ROLE
|
||||
value: gitops-server
|
||||
channel: gitops-1.15
|
||||
installPlanApproval: Automatic
|
||||
name: openshift-gitops-operator
|
||||
source: redhat-operators
|
||||
sourceNamespace: openshift-marketplace
|
||||
@@ -0,0 +1,28 @@
|
||||
apiVersion: cluster.open-cluster-management.io/v1beta1
|
||||
kind: Placement
|
||||
metadata:
|
||||
name: placement-policy-gitops
|
||||
namespace: acm-policies
|
||||
spec:
|
||||
clusterSets:
|
||||
- global
|
||||
predicates:
|
||||
- requiredClusterSelector:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: gitops
|
||||
operator: Exists
|
||||
---
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PlacementBinding
|
||||
metadata:
|
||||
name: binding-policy-gitops
|
||||
namespace: acm-policies
|
||||
placementRef:
|
||||
apiGroup: cluster.open-cluster-management.io
|
||||
kind: Placement
|
||||
name: placement-policy-gitops
|
||||
subjects:
|
||||
- apiGroup: policy.open-cluster-management.io
|
||||
kind: PolicySet
|
||||
name: gitops
|
||||
@@ -0,0 +1,60 @@
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PolicyGenerator
|
||||
metadata:
|
||||
name: gitops-policy-generator
|
||||
policyDefaults:
|
||||
namespace: acm-policies
|
||||
remediationAction: enforce
|
||||
placementBindingDefaults:
|
||||
name: "binding-policy-gitops"
|
||||
policies:
|
||||
- name: policy-eso-secret-store
|
||||
configurationPolicyAnnotations:
|
||||
apps.open-cluster-management.io/reconcile-option: replace
|
||||
manifests:
|
||||
- path: manifests/eso/base/
|
||||
- name: policy-gitops-subscription
|
||||
remediationAction: enforce
|
||||
manifests:
|
||||
- path: manifests/gitops-subscription/base/
|
||||
- name: policy-gitops-instance
|
||||
# Needed to fix issue with merging lists resulting in duplicates
|
||||
configurationPolicyAnnotations:
|
||||
apps.open-cluster-management.io/reconcile-option: replace
|
||||
complianceType: "mustonlyhave"
|
||||
manifests:
|
||||
- path: manifests/gitops-instance/base/
|
||||
- name: policy-gitops-bootstrap
|
||||
manifests:
|
||||
- path: manifests/gitops-bootstrap/base/
|
||||
- name: policy-gitops-notifications
|
||||
remediationAction: enforce
|
||||
manifests:
|
||||
- path: manifests/gitops-notifications/base/
|
||||
configurationPolicyAnnotations:
|
||||
policy.open-cluster-management.io/disable-templates: "true"
|
||||
- name: policy-gitops-alerting
|
||||
remediationAction: enforce
|
||||
manifests:
|
||||
- path: manifests/gitops-alerting/base/
|
||||
configurationPolicyAnnotations:
|
||||
policy.open-cluster-management.io/disable-templates: "true"
|
||||
# Put ESO secrets into separate policy since it's chicken and egg
|
||||
# Not being used since I have a global policy that does this but included for example
|
||||
# - name: policy-gitops-secrets
|
||||
# remediationAction: enforce
|
||||
# manifests:
|
||||
# - path: manifests/gitops-secrets/base/
|
||||
policySets:
|
||||
- name: "gitops"
|
||||
description: "Policy for bootstrapping cluster with gitops"
|
||||
policies:
|
||||
- policy-eso-secret-store
|
||||
- policy-gitops-subscription
|
||||
- policy-gitops-instance
|
||||
- policy-gitops-bootstrap
|
||||
- policy-gitops-notifications
|
||||
- policy-gitops-alerting
|
||||
generatePolicySetPlacement: false
|
||||
placement:
|
||||
name: placement-policy-gitops
|
||||
@@ -0,0 +1,459 @@
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: policy-gatekeeper-livenessprobe
|
||||
annotations:
|
||||
policy.open-cluster-management.io/standards: NIST SP 800-53
|
||||
policy.open-cluster-management.io/categories: CM Configuration Management
|
||||
policy.open-cluster-management.io/controls: CM-2 Baseline Configuration
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
disabled: false
|
||||
policy-templates:
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: policy-gatekeeper-containerlivenessprobenotset
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
severity: low
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: templates.gatekeeper.sh/v1beta1
|
||||
kind: ConstraintTemplate
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: containerlivenessprobenotset
|
||||
spec:
|
||||
crd:
|
||||
spec:
|
||||
names:
|
||||
kind: ContainerLivenessprobeNotset
|
||||
targets:
|
||||
- libs:
|
||||
- |
|
||||
package lib.konstraint
|
||||
|
||||
default is_gatekeeper = false
|
||||
|
||||
is_gatekeeper {
|
||||
has_field(input, "review")
|
||||
has_field(input.review, "object")
|
||||
}
|
||||
|
||||
object = input {
|
||||
not is_gatekeeper
|
||||
}
|
||||
|
||||
object = input.review.object {
|
||||
is_gatekeeper
|
||||
}
|
||||
|
||||
format(msg) = gatekeeper_format {
|
||||
is_gatekeeper
|
||||
gatekeeper_format = {"msg": msg}
|
||||
}
|
||||
|
||||
format(msg) = msg {
|
||||
not is_gatekeeper
|
||||
}
|
||||
|
||||
name = object.metadata.name
|
||||
|
||||
kind = object.kind
|
||||
|
||||
has_field(obj, field) {
|
||||
obj[field]
|
||||
}
|
||||
|
||||
missing_field(obj, field) = true {
|
||||
obj[field] == ""
|
||||
}
|
||||
|
||||
missing_field(obj, field) = true {
|
||||
not has_field(obj, field)
|
||||
}
|
||||
|
||||
is_service {
|
||||
lower(kind) == "service"
|
||||
}
|
||||
|
||||
is_statefulset {
|
||||
lower(kind) == "statefulset"
|
||||
}
|
||||
|
||||
is_daemonset {
|
||||
lower(kind) == "daemonset"
|
||||
}
|
||||
|
||||
is_deployment {
|
||||
lower(kind) == "deployment"
|
||||
}
|
||||
|
||||
is_pod {
|
||||
lower(kind) == "pod"
|
||||
}
|
||||
|
||||
is_namespace {
|
||||
lower(kind) == "namespace"
|
||||
}
|
||||
|
||||
is_workload {
|
||||
containers[_]
|
||||
}
|
||||
|
||||
pod_containers(pod) = all_containers {
|
||||
keys = {"containers", "initContainers"}
|
||||
all_containers = [c | keys[k]; c = pod.spec[k][_]]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
pods[pod]
|
||||
all_containers = pod_containers(pod)
|
||||
container = all_containers[_]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
all_containers = pod_containers(object)
|
||||
container = all_containers[_]
|
||||
}
|
||||
|
||||
container_images[image] {
|
||||
containers[container]
|
||||
image = container.image
|
||||
}
|
||||
|
||||
container_images[image] {
|
||||
image = object.spec.image
|
||||
}
|
||||
|
||||
split_image(image) = [image, "latest"] {
|
||||
not contains(image, ":")
|
||||
}
|
||||
|
||||
split_image(image) = [image_name, tag] {
|
||||
[image_name, tag] = split(image, ":")
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_statefulset
|
||||
pod = object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_daemonset
|
||||
pod = object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_deployment
|
||||
pod = object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_pod
|
||||
pod = object
|
||||
}
|
||||
|
||||
volumes[volume] {
|
||||
pods[pod]
|
||||
volume = pod.spec.volumes[_]
|
||||
}
|
||||
|
||||
mem_multiple("E") = 1000000000000000000000 { true }
|
||||
|
||||
mem_multiple("P") = 1000000000000000000 { true }
|
||||
|
||||
mem_multiple("T") = 1000000000000000 { true }
|
||||
|
||||
mem_multiple("G") = 1000000000000 { true }
|
||||
|
||||
mem_multiple("M") = 1000000000 { true }
|
||||
|
||||
mem_multiple("k") = 1000000 { true }
|
||||
|
||||
mem_multiple("") = 1000 { true }
|
||||
|
||||
mem_multiple("m") = 1 { true }
|
||||
|
||||
mem_multiple("Ki") = 1024000 { true }
|
||||
|
||||
mem_multiple("Mi") = 1048576000 { true }
|
||||
|
||||
mem_multiple("Gi") = 1073741824000 { true }
|
||||
|
||||
mem_multiple("Ti") = 1099511627776000 { true }
|
||||
|
||||
mem_multiple("Pi") = 1125899906842624000 { true }
|
||||
|
||||
mem_multiple("Ei") = 1152921504606846976000 { true }
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
not is_string(mem)
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) > 0
|
||||
suffix := substring(mem, count(mem) - 1, -1)
|
||||
mem_multiple(suffix)
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) > 1
|
||||
suffix := substring(mem, count(mem) - 2, -1)
|
||||
mem_multiple(suffix)
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) > 1
|
||||
not mem_multiple(substring(mem, count(mem) - 1, -1))
|
||||
not mem_multiple(substring(mem, count(mem) - 2, -1))
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) == 1
|
||||
not mem_multiple(substring(mem, count(mem) - 1, -1))
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) == 0
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
canonify_mem(orig) = new {
|
||||
is_number(orig)
|
||||
new := orig * 1000
|
||||
}
|
||||
|
||||
canonify_mem(orig) = new {
|
||||
not is_number(orig)
|
||||
suffix := get_suffix(orig)
|
||||
raw := replace(orig, suffix, "")
|
||||
re_match("^[0-9]+$", raw)
|
||||
new := to_number(raw) * mem_multiple(suffix)
|
||||
}
|
||||
|
||||
canonify_storage(orig) = new {
|
||||
is_number(orig)
|
||||
new := orig
|
||||
}
|
||||
|
||||
canonify_storage(orig) = new {
|
||||
not is_number(orig)
|
||||
suffix := get_suffix(orig)
|
||||
raw := replace(orig, suffix, "")
|
||||
re_match("^[0-9]+$", raw)
|
||||
new := to_number(raw) * mem_multiple(suffix)
|
||||
}
|
||||
|
||||
canonify_cpu(orig) = new {
|
||||
is_number(orig)
|
||||
new := orig * 1000
|
||||
}
|
||||
|
||||
canonify_cpu(orig) = new {
|
||||
not is_number(orig)
|
||||
endswith(orig, "m")
|
||||
new := to_number(replace(orig, "m", ""))
|
||||
}
|
||||
|
||||
canonify_cpu(orig) = new {
|
||||
not is_number(orig)
|
||||
not endswith(orig, "m")
|
||||
re_match("^[0-9]+$", orig)
|
||||
new := to_number(orig) * 1000
|
||||
}
|
||||
|
||||
dropped_capability(container, cap) {
|
||||
container.securityContext.capabilities.drop[_] == cap
|
||||
}
|
||||
|
||||
added_capability(container, cap) {
|
||||
container.securityContext.capabilities.add[_] == cap
|
||||
}
|
||||
|
||||
no_read_only_filesystem(c) {
|
||||
not has_field(c, "securityContext")
|
||||
}
|
||||
|
||||
no_read_only_filesystem(c) {
|
||||
has_field(c, "securityContext")
|
||||
not has_field(c.securityContext, "readOnlyRootFilesystem")
|
||||
}
|
||||
|
||||
priviledge_escalation_allowed(c) {
|
||||
not has_field(c, "securityContext")
|
||||
}
|
||||
|
||||
priviledge_escalation_allowed(c) {
|
||||
has_field(c, "securityContext")
|
||||
has_field(c.securityContext, "allowPrivilegeEscalation")
|
||||
}
|
||||
- |-
|
||||
package lib.openshift
|
||||
|
||||
import data.lib.konstraint
|
||||
|
||||
is_deploymentconfig {
|
||||
lower(konstraint.object.apiVersion) == "apps.openshift.io/v1"
|
||||
lower(konstraint.object.kind) == "deploymentconfig"
|
||||
}
|
||||
|
||||
is_route {
|
||||
lower(konstraint.object.apiVersion) == "route.openshift.io/v1"
|
||||
lower(konstraint.object.kind) == "route"
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
is_deploymentconfig
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
konstraint.is_statefulset
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
konstraint.is_daemonset
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
konstraint.is_deployment
|
||||
}
|
||||
|
||||
is_all_kind {
|
||||
is_workload_kind
|
||||
}
|
||||
|
||||
is_all_kind {
|
||||
konstraint.is_service
|
||||
}
|
||||
|
||||
is_all_kind {
|
||||
is_route
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_deploymentconfig
|
||||
pod = konstraint.object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
pod = konstraint.pods[_]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
pods[pod]
|
||||
all_containers = konstraint.pod_containers(pod)
|
||||
container = all_containers[_]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
container = konstraint.containers[_]
|
||||
}
|
||||
rego: |-
|
||||
package ocp.bestpractices.container_livenessprobe_notset
|
||||
|
||||
import data.lib.konstraint
|
||||
import data.lib.openshift
|
||||
|
||||
violation[msg] {
|
||||
openshift.is_workload_kind
|
||||
|
||||
container := openshift.containers[_]
|
||||
|
||||
konstraint.missing_field(container, "livenessProbe")
|
||||
obj := konstraint.object
|
||||
|
||||
msg := konstraint.format(sprintf("%s/%s: container '%s' has no livenessProbe. See: https://docs.openshift.com/container-platform/latest/applications/application-health.html", [obj.kind, obj.metadata.name, container.name]))
|
||||
}
|
||||
target: admission.k8s.gatekeeper.sh
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: constraints.gatekeeper.sh/v1beta1
|
||||
kind: ContainerLivenessprobeNotset
|
||||
metadata:
|
||||
name: containerlivenessprobenotset
|
||||
spec:
|
||||
enforcementAction: dryrun
|
||||
match:
|
||||
kinds:
|
||||
- apiGroups:
|
||||
- apps.openshift.io
|
||||
- apps
|
||||
kinds:
|
||||
- DeploymentConfig
|
||||
- DaemonSet
|
||||
- Deployment
|
||||
- StatefulSet
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: policy-gatekeeper-audit-liveness
|
||||
spec:
|
||||
remediationAction: inform # will be overridden by remediationAction in parent policy
|
||||
severity: low
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: constraints.gatekeeper.sh/v1beta1
|
||||
kind: ContainerLivenessprobeNotset
|
||||
metadata:
|
||||
name: containerlivenessprobenotset
|
||||
status:
|
||||
totalViolations: 0
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: policy-gatekeeper-admission-liveness
|
||||
spec:
|
||||
remediationAction: inform # will be overridden by remediationAction in parent policy
|
||||
severity: low
|
||||
object-templates:
|
||||
- complianceType: mustnothave
|
||||
objectDefinition:
|
||||
apiVersion: v1
|
||||
kind: Event
|
||||
metadata:
|
||||
namespace: openshift-gatekeeper-system # set it to the actual namespace where gatekeeper is running if different
|
||||
annotations:
|
||||
constraint_action: deny
|
||||
constraint_kind: ContainerLivenessprobeNotset
|
||||
constraint_name: containerlivenessprobenotset
|
||||
event_type: violation
|
||||
---
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PlacementBinding
|
||||
metadata:
|
||||
name: binding-policy-gatekeeper-containerlivenessprobenotset
|
||||
placementRef:
|
||||
name: placement-policy-gatekeeper-containerlivenessprobenotset
|
||||
kind: PlacementRule
|
||||
apiGroup: apps.open-cluster-management.io
|
||||
subjects:
|
||||
- name: policy-gatekeeper-livenessprobe
|
||||
kind: Policy
|
||||
apiGroup: policy.open-cluster-management.io
|
||||
---
|
||||
apiVersion: apps.open-cluster-management.io/v1
|
||||
kind: PlacementRule
|
||||
metadata:
|
||||
name: placement-policy-gatekeeper-containerlivenessprobenotset
|
||||
spec:
|
||||
clusterConditions:
|
||||
- status: "True"
|
||||
type: ManagedClusterConditionAvailable
|
||||
clusterSelector:
|
||||
matchExpressions:
|
||||
- { key: policy, operator: In, values: ["opa"] }
|
||||
@@ -0,0 +1,459 @@
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: policy-gatekeeper-readinessprobe
|
||||
annotations:
|
||||
policy.open-cluster-management.io/standards: NIST SP 800-53
|
||||
policy.open-cluster-management.io/categories: CM Configuration Management
|
||||
policy.open-cluster-management.io/controls: CM-2 Baseline Configuration
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
disabled: false
|
||||
policy-templates:
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: policy-gatekeeper-containerreadinessprobenotset
|
||||
spec:
|
||||
remediationAction: enforce
|
||||
severity: low
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: templates.gatekeeper.sh/v1beta1
|
||||
kind: ConstraintTemplate
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: containerreadinessprobenotset
|
||||
spec:
|
||||
crd:
|
||||
spec:
|
||||
names:
|
||||
kind: ContainerReadinessprobeNotset
|
||||
targets:
|
||||
- libs:
|
||||
- |
|
||||
package lib.konstraint
|
||||
|
||||
default is_gatekeeper = false
|
||||
|
||||
is_gatekeeper {
|
||||
has_field(input, "review")
|
||||
has_field(input.review, "object")
|
||||
}
|
||||
|
||||
object = input {
|
||||
not is_gatekeeper
|
||||
}
|
||||
|
||||
object = input.review.object {
|
||||
is_gatekeeper
|
||||
}
|
||||
|
||||
format(msg) = gatekeeper_format {
|
||||
is_gatekeeper
|
||||
gatekeeper_format = {"msg": msg}
|
||||
}
|
||||
|
||||
format(msg) = msg {
|
||||
not is_gatekeeper
|
||||
}
|
||||
|
||||
name = object.metadata.name
|
||||
|
||||
kind = object.kind
|
||||
|
||||
has_field(obj, field) {
|
||||
obj[field]
|
||||
}
|
||||
|
||||
missing_field(obj, field) = true {
|
||||
obj[field] == ""
|
||||
}
|
||||
|
||||
missing_field(obj, field) = true {
|
||||
not has_field(obj, field)
|
||||
}
|
||||
|
||||
is_service {
|
||||
lower(kind) == "service"
|
||||
}
|
||||
|
||||
is_statefulset {
|
||||
lower(kind) == "statefulset"
|
||||
}
|
||||
|
||||
is_daemonset {
|
||||
lower(kind) == "daemonset"
|
||||
}
|
||||
|
||||
is_deployment {
|
||||
lower(kind) == "deployment"
|
||||
}
|
||||
|
||||
is_pod {
|
||||
lower(kind) == "pod"
|
||||
}
|
||||
|
||||
is_namespace {
|
||||
lower(kind) == "namespace"
|
||||
}
|
||||
|
||||
is_workload {
|
||||
containers[_]
|
||||
}
|
||||
|
||||
pod_containers(pod) = all_containers {
|
||||
keys = {"containers", "initContainers"}
|
||||
all_containers = [c | keys[k]; c = pod.spec[k][_]]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
pods[pod]
|
||||
all_containers = pod_containers(pod)
|
||||
container = all_containers[_]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
all_containers = pod_containers(object)
|
||||
container = all_containers[_]
|
||||
}
|
||||
|
||||
container_images[image] {
|
||||
containers[container]
|
||||
image = container.image
|
||||
}
|
||||
|
||||
container_images[image] {
|
||||
image = object.spec.image
|
||||
}
|
||||
|
||||
split_image(image) = [image, "latest"] {
|
||||
not contains(image, ":")
|
||||
}
|
||||
|
||||
split_image(image) = [image_name, tag] {
|
||||
[image_name, tag] = split(image, ":")
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_statefulset
|
||||
pod = object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_daemonset
|
||||
pod = object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_deployment
|
||||
pod = object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_pod
|
||||
pod = object
|
||||
}
|
||||
|
||||
volumes[volume] {
|
||||
pods[pod]
|
||||
volume = pod.spec.volumes[_]
|
||||
}
|
||||
|
||||
mem_multiple("E") = 1000000000000000000000 { true }
|
||||
|
||||
mem_multiple("P") = 1000000000000000000 { true }
|
||||
|
||||
mem_multiple("T") = 1000000000000000 { true }
|
||||
|
||||
mem_multiple("G") = 1000000000000 { true }
|
||||
|
||||
mem_multiple("M") = 1000000000 { true }
|
||||
|
||||
mem_multiple("k") = 1000000 { true }
|
||||
|
||||
mem_multiple("") = 1000 { true }
|
||||
|
||||
mem_multiple("m") = 1 { true }
|
||||
|
||||
mem_multiple("Ki") = 1024000 { true }
|
||||
|
||||
mem_multiple("Mi") = 1048576000 { true }
|
||||
|
||||
mem_multiple("Gi") = 1073741824000 { true }
|
||||
|
||||
mem_multiple("Ti") = 1099511627776000 { true }
|
||||
|
||||
mem_multiple("Pi") = 1125899906842624000 { true }
|
||||
|
||||
mem_multiple("Ei") = 1152921504606846976000 { true }
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
not is_string(mem)
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) > 0
|
||||
suffix := substring(mem, count(mem) - 1, -1)
|
||||
mem_multiple(suffix)
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) > 1
|
||||
suffix := substring(mem, count(mem) - 2, -1)
|
||||
mem_multiple(suffix)
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) > 1
|
||||
not mem_multiple(substring(mem, count(mem) - 1, -1))
|
||||
not mem_multiple(substring(mem, count(mem) - 2, -1))
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) == 1
|
||||
not mem_multiple(substring(mem, count(mem) - 1, -1))
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
get_suffix(mem) = suffix {
|
||||
is_string(mem)
|
||||
count(mem) == 0
|
||||
suffix := ""
|
||||
}
|
||||
|
||||
canonify_mem(orig) = new {
|
||||
is_number(orig)
|
||||
new := orig * 1000
|
||||
}
|
||||
|
||||
canonify_mem(orig) = new {
|
||||
not is_number(orig)
|
||||
suffix := get_suffix(orig)
|
||||
raw := replace(orig, suffix, "")
|
||||
re_match("^[0-9]+$", raw)
|
||||
new := to_number(raw) * mem_multiple(suffix)
|
||||
}
|
||||
|
||||
canonify_storage(orig) = new {
|
||||
is_number(orig)
|
||||
new := orig
|
||||
}
|
||||
|
||||
canonify_storage(orig) = new {
|
||||
not is_number(orig)
|
||||
suffix := get_suffix(orig)
|
||||
raw := replace(orig, suffix, "")
|
||||
re_match("^[0-9]+$", raw)
|
||||
new := to_number(raw) * mem_multiple(suffix)
|
||||
}
|
||||
|
||||
canonify_cpu(orig) = new {
|
||||
is_number(orig)
|
||||
new := orig * 1000
|
||||
}
|
||||
|
||||
canonify_cpu(orig) = new {
|
||||
not is_number(orig)
|
||||
endswith(orig, "m")
|
||||
new := to_number(replace(orig, "m", ""))
|
||||
}
|
||||
|
||||
canonify_cpu(orig) = new {
|
||||
not is_number(orig)
|
||||
not endswith(orig, "m")
|
||||
re_match("^[0-9]+$", orig)
|
||||
new := to_number(orig) * 1000
|
||||
}
|
||||
|
||||
dropped_capability(container, cap) {
|
||||
container.securityContext.capabilities.drop[_] == cap
|
||||
}
|
||||
|
||||
added_capability(container, cap) {
|
||||
container.securityContext.capabilities.add[_] == cap
|
||||
}
|
||||
|
||||
no_read_only_filesystem(c) {
|
||||
not has_field(c, "securityContext")
|
||||
}
|
||||
|
||||
no_read_only_filesystem(c) {
|
||||
has_field(c, "securityContext")
|
||||
not has_field(c.securityContext, "readOnlyRootFilesystem")
|
||||
}
|
||||
|
||||
priviledge_escalation_allowed(c) {
|
||||
not has_field(c, "securityContext")
|
||||
}
|
||||
|
||||
priviledge_escalation_allowed(c) {
|
||||
has_field(c, "securityContext")
|
||||
has_field(c.securityContext, "allowPrivilegeEscalation")
|
||||
}
|
||||
- |-
|
||||
package lib.openshift
|
||||
|
||||
import data.lib.konstraint
|
||||
|
||||
is_deploymentconfig {
|
||||
lower(konstraint.object.apiVersion) == "apps.openshift.io/v1"
|
||||
lower(konstraint.object.kind) == "deploymentconfig"
|
||||
}
|
||||
|
||||
is_route {
|
||||
lower(konstraint.object.apiVersion) == "route.openshift.io/v1"
|
||||
lower(konstraint.object.kind) == "route"
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
is_deploymentconfig
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
konstraint.is_statefulset
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
konstraint.is_daemonset
|
||||
}
|
||||
|
||||
is_workload_kind {
|
||||
konstraint.is_deployment
|
||||
}
|
||||
|
||||
is_all_kind {
|
||||
is_workload_kind
|
||||
}
|
||||
|
||||
is_all_kind {
|
||||
konstraint.is_service
|
||||
}
|
||||
|
||||
is_all_kind {
|
||||
is_route
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
is_deploymentconfig
|
||||
pod = konstraint.object.spec.template
|
||||
}
|
||||
|
||||
pods[pod] {
|
||||
pod = konstraint.pods[_]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
pods[pod]
|
||||
all_containers = konstraint.pod_containers(pod)
|
||||
container = all_containers[_]
|
||||
}
|
||||
|
||||
containers[container] {
|
||||
container = konstraint.containers[_]
|
||||
}
|
||||
rego: |-
|
||||
package ocp.bestpractices.container_readinessprobe_notset
|
||||
|
||||
import data.lib.konstraint
|
||||
import data.lib.openshift
|
||||
|
||||
violation[msg] {
|
||||
openshift.is_workload_kind
|
||||
|
||||
container := openshift.containers[_]
|
||||
|
||||
konstraint.missing_field(container, "readinessProbe")
|
||||
obj := konstraint.object
|
||||
|
||||
msg := konstraint.format(sprintf("%s/%s: container '%s' has no readinessProbe. See: https://docs.openshift.com/container-platform/4.4/applications/application-health.html", [obj.kind, obj.metadata.name, container.name]))
|
||||
}
|
||||
target: admission.k8s.gatekeeper.sh
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: constraints.gatekeeper.sh/v1beta1
|
||||
kind: ContainerReadinessprobeNotset
|
||||
metadata:
|
||||
name: containerreadinessprobenotset
|
||||
spec:
|
||||
enforcementAction: dryrun
|
||||
match:
|
||||
kinds:
|
||||
- apiGroups:
|
||||
- apps.openshift.io
|
||||
- apps
|
||||
kinds:
|
||||
- DeploymentConfig
|
||||
- DaemonSet
|
||||
- Deployment
|
||||
- StatefulSet
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: policy-gatekeeper-audit-readiness
|
||||
spec:
|
||||
remediationAction: inform # will be overridden by remediationAction in parent policy
|
||||
severity: low
|
||||
object-templates:
|
||||
- complianceType: musthave
|
||||
objectDefinition:
|
||||
apiVersion: constraints.gatekeeper.sh/v1beta1
|
||||
kind: ContainerReadinessprobeNotset
|
||||
metadata:
|
||||
name: containerreadinessprobenotset
|
||||
status:
|
||||
totalViolations: 0
|
||||
- objectDefinition:
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: ConfigurationPolicy
|
||||
metadata:
|
||||
name: policy-gatekeeper-admission-readiness
|
||||
spec:
|
||||
remediationAction: inform # will be overridden by remediationAction in parent policy
|
||||
severity: low
|
||||
object-templates:
|
||||
- complianceType: mustnothave
|
||||
objectDefinition:
|
||||
apiVersion: v1
|
||||
kind: Event
|
||||
metadata:
|
||||
namespace: openshift-gatekeeper-system # set it to the actual namespace where gatekeeper is running if different
|
||||
annotations:
|
||||
constraint_action: deny
|
||||
constraint_kind: ContainerReadinessprobeNotset
|
||||
constraint_name: containerreadinessprobenotset
|
||||
event_type: violation
|
||||
---
|
||||
apiVersion: policy.open-cluster-management.io/v1
|
||||
kind: PlacementBinding
|
||||
metadata:
|
||||
name: binding-policy-gatekeeper-containerreadinessprobenotset
|
||||
placementRef:
|
||||
name: placement-policy-gatekeeper-containerreadinessprobenotset
|
||||
kind: PlacementRule
|
||||
apiGroup: apps.open-cluster-management.io
|
||||
subjects:
|
||||
- name: policy-gatekeeper-readinessprobe
|
||||
kind: Policy
|
||||
apiGroup: policy.open-cluster-management.io
|
||||
---
|
||||
apiVersion: apps.open-cluster-management.io/v1
|
||||
kind: PlacementRule
|
||||
metadata:
|
||||
name: placement-policy-gatekeeper-containerreadinessprobenotset
|
||||
spec:
|
||||
clusterConditions:
|
||||
- status: "True"
|
||||
type: ManagedClusterConditionAvailable
|
||||
clusterSelector:
|
||||
matchExpressions:
|
||||
- { key: policy, operator: In, values: ["opa"] }
|
||||
18
tmp/acm-hub-bootstrap/.ansible-lint
Normal file
18
tmp/acm-hub-bootstrap/.ansible-lint
Normal file
@@ -0,0 +1,18 @@
|
||||
# Vim filetype=yaml
|
||||
---
|
||||
offline: false
|
||||
#requirements: ansible/execution_environment/requirements.yml
|
||||
|
||||
exclude_paths:
|
||||
- .cache/
|
||||
- .github/
|
||||
- charts/
|
||||
- common/
|
||||
- tests/
|
||||
|
||||
# warn_list:
|
||||
# - yaml
|
||||
# - schema
|
||||
# - experimental
|
||||
# - risky-file-permissions
|
||||
# - var-spacing
|
||||
9
tmp/acm-hub-bootstrap/.github/dependabot.yml
vendored
Normal file
9
tmp/acm-hub-bootstrap/.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
version: 2
|
||||
updates:
|
||||
# Check for updates to GitHub Actions every week
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
9
tmp/acm-hub-bootstrap/.github/linters/.gitleaks.toml
vendored
Normal file
9
tmp/acm-hub-bootstrap/.github/linters/.gitleaks.toml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
[whitelist]
|
||||
# As of v4, gitleaks only matches against filename, not path in the
|
||||
# files directive. Leaving content for backwards compatibility.
|
||||
files = [
|
||||
"ansible/plugins/modules/*.py",
|
||||
"ansible/tests/unit/test_*.py",
|
||||
"ansible/tests/unit/*.yaml",
|
||||
"ansible/tests/unit/v2/*.yaml",
|
||||
]
|
||||
6
tmp/acm-hub-bootstrap/.github/linters/.markdown-lint.yml
vendored
Normal file
6
tmp/acm-hub-bootstrap/.github/linters/.markdown-lint.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"default": true,
|
||||
"MD003": false,
|
||||
"MD013": false,
|
||||
"MD033": false
|
||||
}
|
||||
17
tmp/acm-hub-bootstrap/.github/workflows/ansible-lint.yml
vendored
Normal file
17
tmp/acm-hub-bootstrap/.github/workflows/ansible-lint.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: Ansible Lint # feel free to pick your own name
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Important: This sets up your GITHUB_WORKSPACE environment variable
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Lint Ansible Playbook
|
||||
uses: ansible/ansible-lint-action@v6
|
||||
# Let's point it to the path
|
||||
with:
|
||||
path: "ansible/"
|
||||
49
tmp/acm-hub-bootstrap/.github/workflows/jsonschema.yaml
vendored
Normal file
49
tmp/acm-hub-bootstrap/.github/workflows/jsonschema.yaml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Verify json schema
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
jsonschema_tests:
|
||||
name: Json Schema tests
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.11]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install check-jsonschema
|
||||
|
||||
- name: Install yq
|
||||
uses: chrisdickinson/setup-yq@latest
|
||||
with:
|
||||
yq-version: v4.30.7
|
||||
|
||||
- name: Verify secrets json schema against templates
|
||||
run: |
|
||||
cp ./values-secret.yaml.template ./values-secret.yaml
|
||||
check-jsonschema --fill-defaults --schemafile https://raw.githubusercontent.com/validatedpatterns/rhvp.cluster_utils/refs/heads/main/roles/vault_utils/values-secrets.v2.schema.json values-secret.yaml
|
||||
rm -f ./values-secret.yaml
|
||||
|
||||
- name: Verify ClusterGroup values.schema.json against values-*yaml files
|
||||
run: |
|
||||
set -e; for i in values-hub.yaml values-group-one.yaml; do
|
||||
echo "$i"
|
||||
# disable shellcheck of single quotes in yq
|
||||
# shellcheck disable=2016
|
||||
yq eval-all '. as $item ireduce ({}; . * $item )' values-global.yaml "$i" > tmp.yaml
|
||||
check-jsonschema --fill-defaults --schemafile https://raw.githubusercontent.com/validatedpatterns/clustergroup-chart/refs/heads/main/values.schema.json tmp.yaml
|
||||
rm -f tmp.yaml
|
||||
done
|
||||
|
||||
44
tmp/acm-hub-bootstrap/.github/workflows/superlinter.yml
vendored
Normal file
44
tmp/acm-hub-bootstrap/.github/workflows/superlinter.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: Super linter
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Name the Job
|
||||
name: Super linter
|
||||
# Set the agent to run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Full git history is needed to get a proper list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
|
||||
################################
|
||||
# Run Linter against code base #
|
||||
################################
|
||||
- name: Lint Code Base
|
||||
uses: super-linter/super-linter/slim@v7
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: true
|
||||
DEFAULT_BRANCH: main
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# These are the validation we disable atm
|
||||
VALIDATE_ANSIBLE: false
|
||||
VALIDATE_BASH: false
|
||||
VALIDATE_CHECKOV: false
|
||||
VALIDATE_JSCPD: false
|
||||
VALIDATE_JSON_PRETTIER: false
|
||||
VALIDATE_MARKDOWN_PRETTIER: false
|
||||
VALIDATE_KUBERNETES_KUBECONFORM: false
|
||||
VALIDATE_PYTHON_PYLINT: false
|
||||
VALIDATE_SHELL_SHFMT: false
|
||||
VALIDATE_YAML: false
|
||||
VALIDATE_YAML_PRETTIER: false
|
||||
# VALIDATE_DOCKERFILE_HADOLINT: false
|
||||
# VALIDATE_MARKDOWN: false
|
||||
# VALIDATE_NATURAL_LANGUAGE: false
|
||||
# VALIDATE_TEKTON: false
|
||||
23
tmp/acm-hub-bootstrap/.github/workflows/update-metadata.yml
vendored
Normal file
23
tmp/acm-hub-bootstrap/.github/workflows/update-metadata.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# This job requires a secret called DOCS_TOKEN which should be a PAT token
|
||||
# that has the permissions described in:
|
||||
# validatedpatterns/docs/.github/workflows/metadata-docs.yml@main
|
||||
---
|
||||
name: Update docs pattern metadata
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "pattern-metadata.yaml"
|
||||
- ".github/workflows/update-metadata.yml"
|
||||
|
||||
jobs:
|
||||
update-metadata:
|
||||
uses: validatedpatterns/docs/.github/workflows/metadata-docs.yml@main
|
||||
permissions: # Workflow-level permissions
|
||||
contents: read # Required for "read-all"
|
||||
packages: write # Allows writing to packages
|
||||
id-token: write # Allows creating OpenID Connect (OIDC) tokens
|
||||
secrets: inherit
|
||||
# For testing you can point to a different branch in the docs repository
|
||||
# with:
|
||||
# DOCS_BRANCH: "main"
|
||||
9
tmp/acm-hub-bootstrap/.gitignore
vendored
Normal file
9
tmp/acm-hub-bootstrap/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
values-secret*
|
||||
.*.expected.yaml
|
||||
pattern-vault.init
|
||||
vault.init
|
||||
super-linter.log
|
||||
common/pattern-vault.init
|
||||
1
tmp/acm-hub-bootstrap/.gitleaks.toml
Symbolic link
1
tmp/acm-hub-bootstrap/.gitleaks.toml
Symbolic link
@@ -0,0 +1 @@
|
||||
.github/linters/.gitleaks.toml
|
||||
202
tmp/acm-hub-bootstrap/LICENSE
Normal file
202
tmp/acm-hub-bootstrap/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
tmp/acm-hub-bootstrap/Makefile
Normal file
25
tmp/acm-hub-bootstrap/Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
.PHONY: default
|
||||
default: help
|
||||
|
||||
.PHONY: help
|
||||
##@ Pattern tasks
|
||||
|
||||
# No need to add a comment here as help is described in common/
|
||||
help:
|
||||
@make -f common/Makefile MAKEFILE_LIST="Makefile common/Makefile" help
|
||||
|
||||
%:
|
||||
make -f common/Makefile $*
|
||||
|
||||
.PHONY: install
|
||||
install: operator-deploy post-install ## installs the pattern and loads the secrets
|
||||
@echo "Installed"
|
||||
|
||||
.PHONY: post-install
|
||||
post-install: ## Post-install tasks
|
||||
make load-secrets
|
||||
@echo "Done"
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@make -f common/Makefile PATTERN_OPTS="-f values-global.yaml -f values-hub.yaml" test
|
||||
19
tmp/acm-hub-bootstrap/README.md
Normal file
19
tmp/acm-hub-bootstrap/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Multicloud Gitops
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
[Live build status](https://validatedpatterns.io/ci/?pattern=mcgitops)
|
||||
|
||||
## Start Here
|
||||
|
||||
If you've followed a link to this repository, but are not really sure what it contains
|
||||
or how to use it, head over to [Multicloud GitOps](https://validatedpatterns.io/patterns/multicloud-gitops/)
|
||||
for additional context and installation instructions
|
||||
|
||||
## Rationale
|
||||
|
||||
The goal for this pattern is to:
|
||||
|
||||
* Use a GitOps approach to manage hybrid and multi-cloud deployments across both public and private clouds.
|
||||
* Enable cross-cluster governance and application lifecycle management.
|
||||
* Securely manage secrets across the deployment.
|
||||
6
tmp/acm-hub-bootstrap/ansible.cfg
Normal file
6
tmp/acm-hub-bootstrap/ansible.cfg
Normal file
@@ -0,0 +1,6 @@
|
||||
[defaults]
|
||||
localhost_warning=False
|
||||
retry_files_enabled=False
|
||||
library=~/.ansible/plugins/modules:./ansible/plugins/modules:./common/ansible/plugins/modules:/usr/share/ansible/plugins/modules
|
||||
roles_path=~/.ansible/roles:./ansible/roles:./common/ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
|
||||
filter_plugins=~/.ansible/plugins/filter:./ansible/plugins/filter:./common/ansible/plugins/filter:/usr/share/ansible/plugins/filter
|
||||
17
tmp/acm-hub-bootstrap/ansible/site.yaml
Normal file
17
tmp/acm-hub-bootstrap/ansible/site.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
# This is only needed for RHPDS
|
||||
- name: MultiCloud-GitOps RHPDS bootstrap
|
||||
hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
# We cannot use .package or .dnf modules because python3 that is used comes
|
||||
# from a virtualenv
|
||||
- name: Launch the installation
|
||||
ansible.builtin.command: ./pattern.sh make install
|
||||
args:
|
||||
chdir: "{{ lookup('env', 'PWD') }}"
|
||||
register: output
|
||||
changed_when: false
|
||||
|
||||
- name: Print output of installation
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ output }}"
|
||||
6
tmp/acm-hub-bootstrap/charts/all/config-demo/Chart.yaml
Normal file
6
tmp/acm-hub-bootstrap/charts/all/config-demo/Chart.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
description: A Helm chart to build and deploy a use of remote configuration enabled by ACM and Vault
|
||||
keywords:
|
||||
- pattern
|
||||
name: config-demo
|
||||
version: 0.0.1
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: config-demo-configmap
|
||||
labels:
|
||||
app.kubernetes.io/instance: config-demo
|
||||
data:
|
||||
"index.html": |-
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Config Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
Hub Cluster domain is '{{ .Values.global.hubClusterDomain }}' <br>
|
||||
Pod is running on Local Cluster Domain '{{ .Values.global.localClusterDomain }}' <br>
|
||||
</h1>
|
||||
<h2>
|
||||
The secret is <a href="/secret/secret">secret</a>
|
||||
</h2>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,65 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
application: config-demo
|
||||
name: config-demo
|
||||
spec:
|
||||
replicas: 2
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
deploymentconfig: config-demo
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: config-demo
|
||||
deploymentconfig: config-demo
|
||||
name: config-demo
|
||||
spec:
|
||||
containers:
|
||||
- name: apache
|
||||
image: registry.access.redhat.com/ubi8/httpd-24:1-226
|
||||
#imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- mountPath: /var/www/html
|
||||
name: config-demo-configmap
|
||||
- mountPath: /var/www/html/secret
|
||||
readOnly: true
|
||||
name: config-demo-secret
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /index.html
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 5
|
||||
timeoutSeconds: 1
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /index.html
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 5
|
||||
timeoutSeconds: 1
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
volumes:
|
||||
- name: config-demo-configmap
|
||||
configMap:
|
||||
defaultMode: 438
|
||||
name: config-demo-configmap
|
||||
- name: config-demo-secret
|
||||
secret:
|
||||
secretName: config-demo-secret
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
apiVersion: "external-secrets.io/v1beta1"
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: config-demo-secret
|
||||
namespace: config-demo
|
||||
spec:
|
||||
refreshInterval: 15s
|
||||
secretStoreRef:
|
||||
name: {{ .Values.secretStore.name }}
|
||||
kind: {{ .Values.secretStore.kind }}
|
||||
target:
|
||||
name: config-demo-secret
|
||||
template:
|
||||
type: Opaque
|
||||
dataFrom:
|
||||
- extract:
|
||||
key: {{ .Values.configdemosecret.key }}
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
metadata:
|
||||
name: config-demo
|
||||
spec:
|
||||
lookupPolicy:
|
||||
local: true
|
||||
tags:
|
||||
- name: registry.access.redhat.com/ubi8/httpd-24
|
||||
importPolicy: {}
|
||||
referencePolicy:
|
||||
type: Local
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: route.openshift.io/v1
|
||||
kind: Route
|
||||
metadata:
|
||||
labels:
|
||||
app: config-demo
|
||||
name: config-demo
|
||||
spec:
|
||||
port:
|
||||
targetPort: 8080-tcp
|
||||
to:
|
||||
kind: Service
|
||||
name: config-demo
|
||||
weight: 100
|
||||
wildcardPolicy: None
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: config-demo
|
||||
name: config-demo
|
||||
spec:
|
||||
ports:
|
||||
- name: 8080-tcp
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: config-demo
|
||||
deploymentconfig: config-demo
|
||||
sessionAffinity: None
|
||||
type: ClusterIP
|
||||
14
tmp/acm-hub-bootstrap/charts/all/config-demo/values.yaml
Normal file
14
tmp/acm-hub-bootstrap/charts/all/config-demo/values.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
secretStore:
|
||||
name: vault-backend
|
||||
kind: ClusterSecretStore
|
||||
|
||||
configdemosecret:
|
||||
key: secret/data/global/config-demo
|
||||
|
||||
global:
|
||||
hubClusterDomain: hub.example.com
|
||||
localClusterDomain: region-one.example.com
|
||||
|
||||
clusterGroup:
|
||||
isHubCluster: true
|
||||
6
tmp/acm-hub-bootstrap/charts/all/hello-world/Chart.yaml
Normal file
6
tmp/acm-hub-bootstrap/charts/all/hello-world/Chart.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
description: A Helm chart to show a webserver and with no other dependencies
|
||||
keywords:
|
||||
- pattern
|
||||
name: hello-world
|
||||
version: 0.0.1
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: hello-world-configmap
|
||||
labels:
|
||||
app.kubernetes.io/instance: hello-world
|
||||
data:
|
||||
"index.html": |-
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Hello World</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<br/>
|
||||
<h2>
|
||||
Hub Cluster domain is '{{ .Values.global.hubClusterDomain }}' <br>
|
||||
Pod is running on Local Cluster Domain '{{ .Values.global.localClusterDomain }}' <br>
|
||||
</h2>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,58 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
application: hello-world
|
||||
name: hello-world
|
||||
spec:
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
deploymentconfig: hello-world
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hello-world
|
||||
deploymentconfig: hello-world
|
||||
name: hello-world
|
||||
spec:
|
||||
containers:
|
||||
- name: apache
|
||||
image: registry.access.redhat.com/ubi8/httpd-24:1-226
|
||||
#imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- mountPath: /var/www/html
|
||||
name: hello-world-configmap
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /index.html
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 5
|
||||
timeoutSeconds: 1
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /index.html
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 5
|
||||
timeoutSeconds: 1
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
volumes:
|
||||
- name: hello-world-configmap
|
||||
configMap:
|
||||
defaultMode: 438
|
||||
name: hello-world-configmap
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: route.openshift.io/v1
|
||||
kind: Route
|
||||
metadata:
|
||||
labels:
|
||||
app: hello-world
|
||||
name: hello-world
|
||||
spec:
|
||||
port:
|
||||
targetPort: 8080-tcp
|
||||
to:
|
||||
kind: Service
|
||||
name: hello-world
|
||||
weight: 100
|
||||
wildcardPolicy: None
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: hello-world
|
||||
name: hello-world
|
||||
spec:
|
||||
ports:
|
||||
- name: 8080-tcp
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: hello-world
|
||||
deploymentconfig: hello-world
|
||||
sessionAffinity: None
|
||||
type: ClusterIP
|
||||
4
tmp/acm-hub-bootstrap/charts/all/hello-world/values.yaml
Normal file
4
tmp/acm-hub-bootstrap/charts/all/hello-world/values.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
global:
|
||||
hubClusterDomain: hub.example.com
|
||||
localCluster: local.example.com
|
||||
0
tmp/acm-hub-bootstrap/charts/region/.keep
Normal file
0
tmp/acm-hub-bootstrap/charts/region/.keep
Normal file
21
tmp/acm-hub-bootstrap/common/.ansible-lint
Normal file
21
tmp/acm-hub-bootstrap/common/.ansible-lint
Normal file
@@ -0,0 +1,21 @@
|
||||
# Vim filetype=yaml
|
||||
---
|
||||
offline: false
|
||||
skip_list:
|
||||
- name[template] # Allow Jinja templating inside task and play names
|
||||
- template-instead-of-copy # Templated files should use template instead of copy
|
||||
- yaml[line-length] # too long lines
|
||||
- yaml[indentation] # Forcing lists to be always indented by 2 chars is silly IMO
|
||||
- var-naming[no-role-prefix] # This would be too much churn for very little gain
|
||||
- no-changed-when
|
||||
- var-naming[no-role-prefix] # There are too many changes now and it would be too risky
|
||||
|
||||
# ansible-lint gh workflow cannot find ansible.cfg hence fails to import vault_utils role
|
||||
exclude_paths:
|
||||
- ./ansible/playbooks/vault/vault.yaml
|
||||
- ./ansible/playbooks/iib-ci/iib-ci.yaml
|
||||
- ./ansible/playbooks/k8s_secrets/k8s_secrets.yml
|
||||
- ./ansible/playbooks/process_secrets/process_secrets.yml
|
||||
- ./ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml
|
||||
- ./ansible/playbooks/process_secrets/display_secrets_info.yml
|
||||
- ./ansible/roles/vault_utils/tests/test.yml
|
||||
9
tmp/acm-hub-bootstrap/common/.github/dependabot.yml
vendored
Normal file
9
tmp/acm-hub-bootstrap/common/.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
version: 2
|
||||
updates:
|
||||
# Check for updates to GitHub Actions every week
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
4
tmp/acm-hub-bootstrap/common/.github/linters/.gitleaks.toml
vendored
Normal file
4
tmp/acm-hub-bootstrap/common/.github/linters/.gitleaks.toml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[whitelist]
|
||||
# As of v4, gitleaks only matches against filename, not path in the
|
||||
# files directive. Leaving content for backwards compatibility.
|
||||
files = [ ]
|
||||
6
tmp/acm-hub-bootstrap/common/.github/linters/.markdown-lint.yml
vendored
Normal file
6
tmp/acm-hub-bootstrap/common/.github/linters/.markdown-lint.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"default": true,
|
||||
"MD003": false,
|
||||
"MD013": false,
|
||||
"MD033": false
|
||||
}
|
||||
48
tmp/acm-hub-bootstrap/common/.github/workflows/pattern-sh-ci.yml
vendored
Normal file
48
tmp/acm-hub-bootstrap/common/.github/workflows/pattern-sh-ci.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Run Bash Script on Multiple Distributions
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "scripts/**"
|
||||
- "Makefile"
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- "scripts/**"
|
||||
- "Makefile"
|
||||
|
||||
jobs:
|
||||
run-script:
|
||||
name: Run Bash Script
|
||||
strategy:
|
||||
matrix:
|
||||
# Fedora is not an option yet
|
||||
os: [ubuntu-latest, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Podman on Ubuntu
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y podman
|
||||
|
||||
# Currently we do not do MacOSX as it is not free, maybe in the future
|
||||
# - name: Install Podman on macOS
|
||||
# if: contains(matrix.os, 'macos')
|
||||
# run: |
|
||||
# brew install podman
|
||||
# podman machine init
|
||||
# podman machine start
|
||||
|
||||
- name: Verify Podman Installation
|
||||
run: podman --version
|
||||
|
||||
- name: Run pattern.sh script
|
||||
run: |
|
||||
export TARGET_BRANCH=main
|
||||
./scripts/pattern-util.sh make validate-origin
|
||||
44
tmp/acm-hub-bootstrap/common/.github/workflows/superlinter.yml
vendored
Normal file
44
tmp/acm-hub-bootstrap/common/.github/workflows/superlinter.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: Super linter
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Name the Job
|
||||
name: Super linter
|
||||
# Set the agent to run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Full git history is needed to get a proper list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
|
||||
################################
|
||||
# Run Linter against code base #
|
||||
################################
|
||||
- name: Lint Code Base
|
||||
uses: super-linter/super-linter/slim@v7
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: true
|
||||
DEFAULT_BRANCH: main
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# These are the validation we disable atm
|
||||
VALIDATE_ANSIBLE: false
|
||||
VALIDATE_BASH: false
|
||||
VALIDATE_CHECKOV: false
|
||||
VALIDATE_JSCPD: false
|
||||
VALIDATE_JSON_PRETTIER: false
|
||||
VALIDATE_MARKDOWN_PRETTIER: false
|
||||
VALIDATE_KUBERNETES_KUBECONFORM: false
|
||||
VALIDATE_PYTHON_PYLINT: false
|
||||
VALIDATE_SHELL_SHFMT: false
|
||||
VALIDATE_YAML: false
|
||||
VALIDATE_YAML_PRETTIER: false
|
||||
# VALIDATE_DOCKERFILE_HADOLINT: false
|
||||
# VALIDATE_MARKDOWN: false
|
||||
# VALIDATE_NATURAL_LANGUAGE: false
|
||||
# VALIDATE_TEKTON: false
|
||||
13
tmp/acm-hub-bootstrap/common/.gitignore
vendored
Normal file
13
tmp/acm-hub-bootstrap/common/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
values-secret.yaml
|
||||
.*.expected.yaml
|
||||
.vscode
|
||||
pattern-vault.init
|
||||
pattern-vault.init.bak
|
||||
super-linter.log
|
||||
golang-external-secrets/Chart.lock
|
||||
hashicorp-vault/Chart.lock
|
||||
1
tmp/acm-hub-bootstrap/common/.gitleaks.toml
Symbolic link
1
tmp/acm-hub-bootstrap/common/.gitleaks.toml
Symbolic link
@@ -0,0 +1 @@
|
||||
.github/linters/.gitleaks.toml
|
||||
153
tmp/acm-hub-bootstrap/common/Changes.md
Normal file
153
tmp/acm-hub-bootstrap/common/Changes.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Changes
|
||||
|
||||
## Sep 24, 2024
|
||||
|
||||
* Ansible has been moved out of the common code tree, you must use a clustergroup chart that is >= 0.9.1
|
||||
|
||||
## Sep 6, 2024
|
||||
|
||||
* Most charts have been removed from the tree. To get the charts you now have to point to them
|
||||
|
||||
## Sep 25, 2023
|
||||
|
||||
* Upgraded ESO to v0.9.5
|
||||
|
||||
## Aug 17, 2023
|
||||
|
||||
* Introduced support for multisource applications via .chart + .chartVersion
|
||||
|
||||
## Jul 8, 2023
|
||||
|
||||
* Introduced a default of 20 for sync failures retries in argo applications (global override via global.options.applicationRetryLimit
|
||||
and per-app override via .syncPolicy)
|
||||
|
||||
## May 22, 2023
|
||||
|
||||
* Upgraded ESO to 0.8.2
|
||||
* *Important* we now use the newly blessed sso config for argo. This means that gitops < 1.8 are *unsupported*
|
||||
|
||||
## May 18, 2023
|
||||
|
||||
* Introduce a EXTRA_HELM_OPTS env variable that will be passed to the helm invocations
|
||||
|
||||
## April 21, 2023
|
||||
|
||||
* Added labels and annotation support to namespaces.yaml template
|
||||
|
||||
## Apr 11, 2023
|
||||
|
||||
* Apply the ACM ocp-gitops-policy everywhere but the hub
|
||||
|
||||
## Apr 7, 2023
|
||||
|
||||
* Moved to gitops-1.8 channel by default (stable is unmaintained and will be dropped starting with ocp-4.13)
|
||||
|
||||
## March 20, 2023
|
||||
|
||||
* Upgraded ESO to 0.8.1
|
||||
|
||||
## February 9, 2023
|
||||
|
||||
* Add support for /values-<platform>.yaml and for /values-<platform>-<clusterversion>.yaml
|
||||
|
||||
## January 29, 2023
|
||||
|
||||
* Stop extracting the HUB's CA via an imperative job running on the imported cluster.
|
||||
Just use ACM to push the HUB's CA out to the managed clusters.
|
||||
|
||||
## January 23, 2023
|
||||
|
||||
* Add initial support for running ESO on ACM-imported clusters
|
||||
|
||||
## January 18, 2023
|
||||
|
||||
* Add validate-schema target
|
||||
|
||||
## January 13, 2023
|
||||
|
||||
* Simplify the secrets paths when using argo hosted sites
|
||||
|
||||
## January 10, 2023
|
||||
|
||||
* vaultPrefixes is now optional in the v2 secret spec and defaults to ["hub"]
|
||||
|
||||
## December 9, 2022
|
||||
|
||||
* Dropped insecureUnsealVaultInsideCluster (and file_unseal) entirely. Now
|
||||
vault is always unsealed via a cronjob in the cluster. It is recommended to
|
||||
store the imperative/vaultkeys secret offline securely and then delete it.
|
||||
|
||||
## December 8, 2022
|
||||
|
||||
* Removed the legacy installation targets:
|
||||
`deploy upgrade legacy-deploy legacy-upgrade`
|
||||
Patterns must now use the operator-based installation
|
||||
|
||||
## November 29, 2022
|
||||
|
||||
* Upgraded vault-helm to 0.23.0
|
||||
* Enable vault-ssl by default
|
||||
|
||||
## November 22, 2022
|
||||
|
||||
* Implemented a new format for the values-secret.yaml. Example can be found in examples/ folder
|
||||
* Now the order of values-secret file lookup is the following:
|
||||
1. ~/values-secret-<patternname>.yaml
|
||||
2. ~/values-secret.yaml
|
||||
3. <patterngitrepo>/values-secret.yaml.template
|
||||
* Add support for ansible vault encrypted values-secret files. You can now encrypt your values-secret file
|
||||
at rest with `ansible-vault encrypt ~/values-secret.yaml`. When running `make load-secrets` if an encrypted
|
||||
file is encountered the user will be prompted automatically for the password to decrypt it.
|
||||
|
||||
## November 6, 2022
|
||||
|
||||
* Add support for /values-<CloudPlatform>-<clusterGroup>.yaml (e.g. /values-AWS-group-one.yaml)
|
||||
|
||||
## October 28, 2022
|
||||
|
||||
* Updated vault helm chart to v0.22.1 and vault containers to 1.12.0
|
||||
|
||||
## October 25, 2022
|
||||
|
||||
* Updated External Secrets Operator to v0.6.0
|
||||
* Moved to -UBI based ESO containers
|
||||
|
||||
## October 13, 2022
|
||||
|
||||
* Added global.clusterVersion as a new helm variable which represents the OCP
|
||||
Major.Minor cluster version. By default now a user can add a
|
||||
values-<ocpversion>-<clustergroup>.yaml file to have specific cluster version
|
||||
overrides (e.g. values-4.10-hub.yaml). Will need Validated Patterns Operator >= 0.0.6
|
||||
when deploying with the operator. Note: When using the ArgoCD Hub and spoke model,
|
||||
you cannot have spokes with a different version of OCP than the hub.
|
||||
|
||||
## October 4, 2022
|
||||
|
||||
* Extended the values-secret.yaml file to support multiple vault paths and re-wrote
|
||||
the push_secrets feature as python module plugin. This requires the following line
|
||||
in a pattern's ansible.cfg's '[defaults]' stanza:
|
||||
|
||||
`library=~/.ansible/plugins/modules:./ansible/plugins/modules:./common/ansible/plugins/modules:/usr/share/ansible/plugins/modules`
|
||||
|
||||
## October 3, 2022
|
||||
|
||||
* Restore the ability to install a non-default site: `make TARGET_SITE=mysite install`
|
||||
* Revised tests (new output and filenames, requires adding new result files to Git)
|
||||
* ACM 2.6 required for ACM-based managed sites
|
||||
* Introduced global.clusterDomain template variable (without the `apps.` prefix)
|
||||
* Removed the ability to send specific charts to another cluster, use hosted argo sites instead
|
||||
* Added the ability to have the hub host `values-{site}.yaml` for spoke clusters.
|
||||
|
||||
The following example would deploy the namespaces, subscriptions, and
|
||||
applications defined in `values-group-one.yaml` to the `perth` cluster
|
||||
directly from ArgoCD on the hub.
|
||||
|
||||
```yaml
|
||||
managedClusterGroups:
|
||||
- name: group-one
|
||||
hostedArgoSites:
|
||||
- name: perth
|
||||
domain: perth1.beekhof.net
|
||||
bearerKeyPath: secret/data/hub/cluster_perth
|
||||
caKeyPath: secret/data/hub/cluster_perth_ca
|
||||
```
|
||||
202
tmp/acm-hub-bootstrap/common/LICENSE
Normal file
202
tmp/acm-hub-bootstrap/common/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
255
tmp/acm-hub-bootstrap/common/Makefile
Normal file
255
tmp/acm-hub-bootstrap/common/Makefile
Normal file
@@ -0,0 +1,255 @@
|
||||
NAME ?= $(shell basename "`pwd`")
|
||||
|
||||
ifneq ($(origin TARGET_SITE), undefined)
|
||||
TARGET_SITE_OPT=--set main.clusterGroupName=$(TARGET_SITE)
|
||||
endif
|
||||
|
||||
# This variable can be set in order to pass additional helm arguments from the
|
||||
# the command line. I.e. we can set things without having to tweak values files
|
||||
EXTRA_HELM_OPTS ?=
|
||||
|
||||
# This variable can be set in order to pass additional ansible-playbook arguments from the
|
||||
# the command line. I.e. we can set -vvv for more verbose logging
|
||||
EXTRA_PLAYBOOK_OPTS ?=
|
||||
|
||||
# INDEX_IMAGES=registry-proxy.engineering.redhat.com/rh-osbs/iib:394248
|
||||
# or
|
||||
# INDEX_IMAGES=registry-proxy.engineering.redhat.com/rh-osbs/iib:394248,registry-proxy.engineering.redhat.com/rh-osbs/iib:394249
|
||||
INDEX_IMAGES ?=
|
||||
|
||||
TARGET_ORIGIN ?= origin
|
||||
# This is to ensure that whether we start with a git@ or https:// URL, we end up with an https:// URL
|
||||
# This is because we expect to use tokens for repo authentication as opposed to SSH keys
|
||||
TARGET_REPO=$(shell git ls-remote --get-url --symref $(TARGET_ORIGIN) | sed -e 's/.*URL:[[:space:]]*//' -e 's%^git@%%' -e 's%^https://%%' -e 's%:%/%' -e 's%^%https://%')
|
||||
# git branch --show-current is also available as of git 2.22, but we will use this for compatibility
|
||||
TARGET_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
UUID_FILE ?= ~/.config/validated-patterns/pattern-uuid
|
||||
UUID_HELM_OPTS ?=
|
||||
|
||||
# --set values always take precedence over the contents of -f
|
||||
ifneq ("$(wildcard $(UUID_FILE))","")
|
||||
UUID := $(shell cat $(UUID_FILE))
|
||||
UUID_HELM_OPTS := --set main.analyticsUUID=$(UUID)
|
||||
endif
|
||||
|
||||
# Set the secret name *and* its namespace when deploying from private repositories
|
||||
# The format of said secret is documented here: https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#repositories
|
||||
TOKEN_SECRET ?=
|
||||
TOKEN_NAMESPACE ?=
|
||||
|
||||
ifeq ($(TOKEN_SECRET),)
|
||||
HELM_OPTS=-f values-global.yaml --set main.git.repoURL="$(TARGET_REPO)" --set main.git.revision=$(TARGET_BRANCH) $(TARGET_SITE_OPT) $(UUID_HELM_OPTS) $(EXTRA_HELM_OPTS)
|
||||
else
|
||||
# When we are working with a private repository we do not escape the git URL as it might be using an ssh secret which does not use https://
|
||||
TARGET_CLEAN_REPO=$(shell git ls-remote --get-url --symref $(TARGET_ORIGIN))
|
||||
HELM_OPTS=-f values-global.yaml --set main.tokenSecret=$(TOKEN_SECRET) --set main.tokenSecretNamespace=$(TOKEN_NAMESPACE) --set main.git.repoURL="$(TARGET_CLEAN_REPO)" --set main.git.revision=$(TARGET_BRANCH) $(TARGET_SITE_OPT) $(UUID_HELM_OPTS) $(EXTRA_HELM_OPTS)
|
||||
endif
|
||||
|
||||
# Helm does the right thing and fetches all the tags and detects the newest one
|
||||
PATTERN_INSTALL_CHART ?= oci://quay.io/hybridcloudpatterns/pattern-install
|
||||
|
||||
##@ Pattern Common Tasks
|
||||
|
||||
.PHONY: help
|
||||
help: ## This help message
|
||||
@echo "Pattern: $(NAME)"
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^(\s|[a-zA-Z_0-9-])+:.*?##/ { printf " \033[36m%-35s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
# Makefiles in the individual patterns should call these targets explicitly
|
||||
# e.g. from industrial-edge: make -f common/Makefile show
|
||||
.PHONY: show
|
||||
show: ## show the starting template without installing it
|
||||
helm template $(PATTERN_INSTALL_CHART) --name-template $(NAME) $(HELM_OPTS)
|
||||
|
||||
preview-all: ## (EXPERIMENTAL) Previews all applications on hub and managed clusters
|
||||
@echo "NOTE: This is just a tentative approximation of rendering all hub and managed clusters templates"
|
||||
@common/scripts/preview-all.sh $(TARGET_REPO) $(TARGET_BRANCH)
|
||||
|
||||
preview-%:
|
||||
$(eval CLUSTERGROUP ?= $(shell yq ".main.clusterGroupName" values-global.yaml))
|
||||
@common/scripts/preview.sh $(CLUSTERGROUP) $* $(TARGET_REPO) $(TARGET_BRANCH)
|
||||
|
||||
.PHONY: operator-deploy
|
||||
operator-deploy operator-upgrade: validate-prereq validate-origin validate-cluster ## runs helm install
|
||||
@common/scripts/deploy-pattern.sh $(NAME) $(PATTERN_INSTALL_CHART) $(HELM_OPTS)
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall: ## runs helm uninstall
|
||||
$(eval CSV := $(shell oc get subscriptions -n openshift-operators openshift-gitops-operator -ojsonpath={.status.currentCSV}))
|
||||
helm uninstall $(NAME)
|
||||
@oc delete csv -n openshift-operators $(CSV)
|
||||
|
||||
.PHONY: load-secrets
|
||||
load-secrets: ## loads the secrets into the backend determined by values-global setting
|
||||
common/scripts/process-secrets.sh $(NAME)
|
||||
|
||||
.PHONY: legacy-load-secrets
|
||||
legacy-load-secrets: ## loads the secrets into vault (only)
|
||||
common/scripts/vault-utils.sh push_secrets $(NAME)
|
||||
|
||||
.PHONY: secrets-backend-vault
|
||||
secrets-backend-vault: ## Edits values files to use default Vault+ESO secrets config
|
||||
common/scripts/set-secret-backend.sh vault
|
||||
common/scripts/manage-secret-app.sh vault present
|
||||
common/scripts/manage-secret-app.sh golang-external-secrets present
|
||||
common/scripts/manage-secret-namespace.sh validated-patterns-secrets absent
|
||||
@git diff --exit-code || echo "Secrets backend set to vault, please review changes, commit, and push to activate in the pattern"
|
||||
|
||||
.PHONY: secrets-backend-kubernetes
|
||||
secrets-backend-kubernetes: ## Edits values file to use Kubernetes+ESO secrets config
|
||||
common/scripts/set-secret-backend.sh kubernetes
|
||||
common/scripts/manage-secret-namespace.sh validated-patterns-secrets present
|
||||
common/scripts/manage-secret-app.sh vault absent
|
||||
common/scripts/manage-secret-app.sh golang-external-secrets present
|
||||
@git diff --exit-code || echo "Secrets backend set to kubernetes, please review changes, commit, and push to activate in the pattern"
|
||||
|
||||
.PHONY: secrets-backend-none
|
||||
secrets-backend-none: ## Edits values files to remove secrets manager + ESO
|
||||
common/scripts/set-secret-backend.sh none
|
||||
common/scripts/manage-secret-app.sh vault absent
|
||||
common/scripts/manage-secret-app.sh golang-external-secrets absent
|
||||
common/scripts/manage-secret-namespace.sh validated-patterns-secrets absent
|
||||
@git diff --exit-code || echo "Secrets backend set to none, please review changes, commit, and push to activate in the pattern"
|
||||
|
||||
.PHONY: load-iib
|
||||
load-iib: ## CI target to install Index Image Bundles
|
||||
@set -e; if [ x$(INDEX_IMAGES) != x ]; then \
|
||||
ansible-playbook $(EXTRA_PLAYBOOK_OPTS) rhvp.cluster_utils.iib_ci; \
|
||||
else \
|
||||
echo "No INDEX_IMAGES defined. Bailing out"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: token-kubeconfig
|
||||
token-kubeconfig: ## Create a local ~/.kube/config with password (not usually needed)
|
||||
common/scripts/write-token-kubeconfig.sh
|
||||
|
||||
##@ Validation Tasks
|
||||
|
||||
# We only check the remote ssh git branch's existance if we're not running inside a container
|
||||
# as getting ssh auth working inside a container seems a bit brittle
|
||||
# If the main repoUpstreamURL field is set, then we need to check against
|
||||
# that and not target_repo
|
||||
.PHONY: validate-origin
|
||||
validate-origin: ## verify the git origin is available
|
||||
@echo "Checking repository:"
|
||||
$(eval UPSTREAMURL := $(shell yq -r '.main.git.repoUpstreamURL // (.main.git.repoUpstreamURL = "")' values-global.yaml))
|
||||
@if [ -z "$(UPSTREAMURL)" ]; then\
|
||||
echo -n " $(TARGET_REPO) - branch '$(TARGET_BRANCH)': ";\
|
||||
git ls-remote --exit-code --heads $(TARGET_REPO) $(TARGET_BRANCH) >/dev/null &&\
|
||||
echo "OK" || (echo "NOT FOUND"; exit 1);\
|
||||
else\
|
||||
echo "Upstream URL set to: $(UPSTREAMURL)";\
|
||||
echo -n " $(UPSTREAMURL) - branch '$(TARGET_BRANCH)': ";\
|
||||
git ls-remote --exit-code --heads $(UPSTREAMURL) $(TARGET_BRANCH) >/dev/null &&\
|
||||
echo "OK" || (echo "NOT FOUND"; exit 1);\
|
||||
fi
|
||||
|
||||
.PHONY: validate-cluster
|
||||
validate-cluster: ## Do some cluster validations before installing
|
||||
@echo "Checking cluster:"
|
||||
@echo -n " cluster-info: "
|
||||
@oc cluster-info >/dev/null && echo "OK" || (echo "Error"; exit 1)
|
||||
@echo -n " storageclass: "
|
||||
@if [ `oc get storageclass -o go-template='{{printf "%d\n" (len .items)}}'` -eq 0 ]; then\
|
||||
echo "WARNING: No storageclass found";\
|
||||
else\
|
||||
echo "OK";\
|
||||
fi
|
||||
|
||||
|
||||
.PHONY: validate-schema
|
||||
validate-schema: ## validates values files against schema in common/clustergroup
|
||||
$(eval VAL_PARAMS := $(shell for i in ./values-*.yaml; do echo -n "$${i} "; done))
|
||||
@echo -n "Validating clustergroup schema of: "
|
||||
@set -e; for i in $(VAL_PARAMS); do echo -n " $$i"; helm template oci://quay.io/hybridcloudpatterns/clustergroup $(HELM_OPTS) -f "$${i}" >/dev/null; done
|
||||
@echo
|
||||
|
||||
.PHONY: validate-prereq
|
||||
validate-prereq: ## verify pre-requisites
|
||||
$(eval GLOBAL_PATTERN := $(shell yq -r .global.pattern values-global.yaml))
|
||||
@if [ $(NAME) != $(GLOBAL_PATTERN) ]; then\
|
||||
echo "";\
|
||||
echo "WARNING: folder directory is \"$(NAME)\" and global.pattern is set to \"$(GLOBAL_PATTERN)\"";\
|
||||
echo "this can create problems. Please make sure they are the same!";\
|
||||
echo "";\
|
||||
fi
|
||||
@if [ ! -f /run/.containerenv ]; then\
|
||||
echo "Checking prerequisites:";\
|
||||
echo -n " Check for python-kubernetes: ";\
|
||||
if ! ansible -m ansible.builtin.command -a "{{ ansible_python_interpreter }} -c 'import kubernetes'" localhost > /dev/null 2>&1; then echo "Not found"; exit 1; fi;\
|
||||
echo "OK";\
|
||||
echo -n " Check for kubernetes.core collection: ";\
|
||||
if ! ansible-galaxy collection list | grep kubernetes.core > /dev/null 2>&1; then echo "Not found"; exit 1; fi;\
|
||||
echo "OK";\
|
||||
else\
|
||||
if [ -f values-global.yaml ]; then\
|
||||
OUT=`yq -r '.main.multiSourceConfig.enabled // (.main.multiSourceConfig.enabled = "false")' values-global.yaml`;\
|
||||
if [ "$${OUT,,}" = "false" ]; then\
|
||||
echo "You must set \".main.multiSourceConfig.enabled: true\" in your 'values-global.yaml' file";\
|
||||
echo "because your common subfolder is the slimmed down version with no helm charts in it";\
|
||||
exit 1;\
|
||||
fi;\
|
||||
fi;\
|
||||
fi
|
||||
|
||||
.PHONY: argo-healthcheck
|
||||
argo-healthcheck: ## Checks if all argo applications are synced
|
||||
@echo "Checking argo applications"
|
||||
$(eval APPS := $(shell oc get applications.argoproj.io -A -o jsonpath='{range .items[*]}{@.metadata.namespace}{","}{@.metadata.name}{"\n"}{end}'))
|
||||
@NOTOK=0; \
|
||||
for i in $(APPS); do\
|
||||
n=`echo "$${i}" | cut -f1 -d,`;\
|
||||
a=`echo "$${i}" | cut -f2 -d,`;\
|
||||
STATUS=`oc get -n "$${n}" applications.argoproj.io/"$${a}" -o jsonpath='{.status.sync.status}'`;\
|
||||
if [[ $$STATUS != "Synced" ]]; then\
|
||||
NOTOK=$$(( $${NOTOK} + 1));\
|
||||
fi;\
|
||||
HEALTH=`oc get -n "$${n}" applications.argoproj.io/"$${a}" -o jsonpath='{.status.health.status}'`;\
|
||||
if [[ $$HEALTH != "Healthy" ]]; then\
|
||||
NOTOK=$$(( $${NOTOK} + 1));\
|
||||
fi;\
|
||||
echo "$${n} $${a} -> Sync: $${STATUS} - Health: $${HEALTH}";\
|
||||
done;\
|
||||
if [ $${NOTOK} -gt 0 ]; then\
|
||||
echo "Some applications are not synced or are unhealthy";\
|
||||
exit 1;\
|
||||
fi
|
||||
|
||||
|
||||
##@ Test and Linters Tasks
|
||||
|
||||
.PHONY: qe-tests
|
||||
qe-tests: ## Runs the tests that QE runs
|
||||
@set -e; if [ -f ./tests/interop/run_tests.sh ]; then \
|
||||
pushd ./tests/interop; ./run_tests.sh; popd; \
|
||||
else \
|
||||
echo "No ./tests/interop/run_tests.sh found skipping"; \
|
||||
fi
|
||||
|
||||
.PHONY: super-linter
|
||||
super-linter: ## Runs super linter locally
|
||||
rm -rf .mypy_cache
|
||||
podman run -e RUN_LOCAL=true -e USE_FIND_ALGORITHM=true \
|
||||
-e VALIDATE_ANSIBLE=false \
|
||||
-e VALIDATE_BASH=false \
|
||||
-e VALIDATE_CHECKOV=false \
|
||||
-e VALIDATE_DOCKERFILE_HADOLINT=false \
|
||||
-e VALIDATE_JSCPD=false \
|
||||
-e VALIDATE_JSON_PRETTIER=false \
|
||||
-e VALIDATE_MARKDOWN_PRETTIER=false \
|
||||
-e VALIDATE_KUBERNETES_KUBECONFORM=false \
|
||||
-e VALIDATE_PYTHON_PYLINT=false \
|
||||
-e VALIDATE_SHELL_SHFMT=false \
|
||||
-e VALIDATE_TEKTON=false \
|
||||
-e VALIDATE_YAML=false \
|
||||
-e VALIDATE_YAML_PRETTIER=false \
|
||||
$(DISABLE_LINTERS) \
|
||||
-v $(PWD):/tmp/lint:rw,z \
|
||||
-w /tmp/lint \
|
||||
ghcr.io/super-linter/super-linter:slim-v7
|
||||
|
||||
.PHONY: deploy upgrade legacy-deploy legacy-upgrade
|
||||
deploy upgrade legacy-deploy legacy-upgrade:
|
||||
@echo "UNSUPPORTED TARGET: please switch to 'operator-deploy'"; exit 1
|
||||
51
tmp/acm-hub-bootstrap/common/README.md
Normal file
51
tmp/acm-hub-bootstrap/common/README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Validated Patterns common/ repository
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
## Note
|
||||
|
||||
This is the `main` branch of common and it assumes that the pattern is fully
|
||||
multisource (meaning that any used charts from VP is actually referenced from
|
||||
either a helm chart repository or quay repository). I.e. there are no helm
|
||||
charts contained in this branch of common and there is no ansible code neither.
|
||||
|
||||
The helm charts now live in separate repositories under the VP
|
||||
[organization](https://github.com/validatedpatterns) on GitHub. The repositories are:
|
||||
|
||||
- clustergroup-chart
|
||||
- pattern-install-chart
|
||||
- hashicorp-vault-chart
|
||||
- golang-external-secrets-chart
|
||||
- acm-chart
|
||||
- letsencrypt-chart
|
||||
|
||||
The ansible bits live in this [repository](https://github.com/validatedpatterns/rhvp.cluster_utils)
|
||||
|
||||
In order to be able to use this "slimmed-down" main branch of common you *must*
|
||||
use a 0.9.* clustergroup-chart that. Add the following to your `values-global.yaml`:
|
||||
|
||||
```yaml
|
||||
main:
|
||||
multiSourceConfig:
|
||||
enabled: true
|
||||
clusterGroupChartVersion: 0.9.*
|
||||
```
|
||||
|
||||
## Start Here
|
||||
|
||||
This repository is never used as standalone. It is usually imported in each pattern as a subtree.
|
||||
In order to import the common subtree the very first time you can use the script
|
||||
[make_common_subtree.sh](scripts/make-common-subtree.sh).
|
||||
|
||||
In order to update your common subtree inside your pattern repository you can either use
|
||||
`https://github.com/validatedpatterns/utilities/blob/main/scripts/update-common-everywhere.sh` or
|
||||
do it manually with the following commands:
|
||||
|
||||
```sh
|
||||
git remote add -f common-upstream https://github.com/validatedpatterns/common.git
|
||||
git merge -s subtree -Xtheirs -Xsubtree=common common-upstream/main
|
||||
```
|
||||
|
||||
## Secrets
|
||||
|
||||
There are two different secret formats parsed by the ansible bits. Both are documented [here](https://github.com/validatedpatterns/common/tree/main/ansible/roles/vault_utils/README.md)
|
||||
4
tmp/acm-hub-bootstrap/common/requirements.yml
Normal file
4
tmp/acm-hub-bootstrap/common/requirements.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
# Define Ansible collection requirements here
|
||||
collections:
|
||||
- name: git+https://github.com/validatedpatterns/rhvp.cluster_utils.git,v1
|
||||
27
tmp/acm-hub-bootstrap/common/scripts/deploy-pattern.sh
Executable file
27
tmp/acm-hub-bootstrap/common/scripts/deploy-pattern.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
set -o pipefail
|
||||
|
||||
RUNS=10
|
||||
WAIT=15
|
||||
# Retry five times because the CRD might not be fully installed yet
|
||||
echo -n "Installing pattern: "
|
||||
for i in $(seq 1 ${RUNS}); do \
|
||||
exec 3>&1 4>&2
|
||||
OUT=$( { helm template --include-crds --name-template $* 2>&4 | oc apply -f- 2>&4 1>&3; } 4>&1 3>&1)
|
||||
ret=$?
|
||||
exec 3>&- 4>&-
|
||||
if [ ${ret} -eq 0 ]; then
|
||||
break;
|
||||
else
|
||||
echo -n "."
|
||||
sleep "${WAIT}"
|
||||
fi
|
||||
done
|
||||
|
||||
# All the runs failed
|
||||
if [ ${i} -eq ${RUNS} ]; then
|
||||
echo "Installation failed [${i}/${RUNS}]. Error:"
|
||||
echo "${OUT}"
|
||||
exit 1
|
||||
fi
|
||||
echo "Done"
|
||||
16
tmp/acm-hub-bootstrap/common/scripts/determine-main-clustergroup.sh
Executable file
16
tmp/acm-hub-bootstrap/common/scripts/determine-main-clustergroup.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
PATTERN_DIR="$1"
|
||||
|
||||
if [ -z "$PATTERN_DIR" ]; then
|
||||
PATTERN_DIR="."
|
||||
fi
|
||||
|
||||
CGNAME=$(yq '.main.clusterGroupName' "$PATTERN_DIR/values-global.yaml")
|
||||
|
||||
if [ -z "$CGNAME" ] || [ "$CGNAME" == "null" ]; then
|
||||
echo "Error - cannot detrmine clusterGroupName"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$CGNAME"
|
||||
15
tmp/acm-hub-bootstrap/common/scripts/determine-pattern-name.sh
Executable file
15
tmp/acm-hub-bootstrap/common/scripts/determine-pattern-name.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATTERN_DIR="$1"
|
||||
|
||||
if [ -z "$PATTERN_DIR" ]; then
|
||||
PATTERN_DIR="."
|
||||
fi
|
||||
|
||||
PATNAME=$(yq '.global.pattern' "$PATTERN_DIR/values-global.yaml" 2>/dev/null)
|
||||
|
||||
if [ -z "$PATNAME" ] || [ "$PATNAME" == "null" ]; then
|
||||
PATNAME="$(basename "$PWD")"
|
||||
fi
|
||||
|
||||
echo "$PATNAME"
|
||||
15
tmp/acm-hub-bootstrap/common/scripts/determine-secretstore-backend.sh
Executable file
15
tmp/acm-hub-bootstrap/common/scripts/determine-secretstore-backend.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATTERN_DIR="$1"
|
||||
|
||||
if [ -z "$PATTERN_DIR" ]; then
|
||||
PATTERN_DIR="."
|
||||
fi
|
||||
|
||||
BACKEND=$(yq '.global.secretStore.backend' "$PATTERN_DIR/values-global.yaml" 2>/dev/null)
|
||||
|
||||
if [ -z "$BACKEND" -o "$BACKEND" == "null" ]; then
|
||||
BACKEND="vault"
|
||||
fi
|
||||
|
||||
echo "$BACKEND"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user