Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@

.DEFAULT_GOAL := help

# Possible envs are gcp, e2e-gcp, kind, e2e-kind
# Possible envs are gcp, e2e-gcp, kind, e2e-kind, oci
# Default to gcp
HELMFILE_ENV ?= gcp


ifeq ($(findstring gcp,$(HELMFILE_ENV)),)
ifeq ($(HELMFILE_ENV),oci)
-include env.oci
else ifeq ($(findstring gcp,$(HELMFILE_ENV)),)
-include env.kind
else
-include env.gcp
Expand Down Expand Up @@ -273,8 +275,9 @@ check-helmfile-env-generated: ## Check that the generated directory exists based
elif [ "$(HELMFILE_ENV)" = "kind" ]; then \
test -d $(GENERATED_RABBITMQ_DIR) || { echo "ERROR: generated-values-rabbitmq directory does not exist"; exit 1; }; \
echo "OK: generated-values-rabbitmq directory exists"; \
else \
echo "OK: no generated values needed for environment: $(HELMFILE_ENV)"; \
fi
@echo "OK: Did not need to validate generated values for environment: $(HELMFILE_ENV)"


.PHONY: check-kubectl-context
Expand All @@ -299,9 +302,12 @@ check-kubectl-context: check-kubectl ## Verify kubectl context matches HELMFILE_
exit 1; \
fi \
;; \
oci) \
echo "OK: connected to OCI/OKE cluster (context: $$CONTEXT)"; \
;; \
*) \
echo "ERROR: invalid HELMFILE_ENV: $(HELMFILE_ENV)"; \
echo " Valid values: gcp, e2e-gcp, kind, e2e-kind"; \
echo " Valid values: gcp, e2e-gcp, kind, e2e-kind, oci"; \
exit 1 \
;; \
esac \
Expand Down Expand Up @@ -372,7 +378,7 @@ help: ## Show this help message
@echo ""
@echo "Usage: make [target] [VARIABLE=value ...]"
@echo ""
@echo "Environment: HELMFILE_ENV=$(HELMFILE_ENV) (gcp|kind|e2e-gcp|e2e-kind)"
@echo "Environment: HELMFILE_ENV=$(HELMFILE_ENV) (gcp|kind|e2e-gcp|e2e-kind|oci)"
@echo ""
@awk '/^# ====/ { \
section = $$0; \
Expand All @@ -397,6 +403,16 @@ help: ## Show this help message



# ==== OCI/OKE Deployment Targets ====

.PHONY: install-all-oci
install-all-oci: check-helmfile-env ## Full OCI/OKE install (rabbitmq + api + sentinel + adapter1 via helmfile)
helmfile -f helmfile/helmfile.yaml.gotmpl -e $(HELMFILE_ENV) apply

.PHONY: uninstall-all-oci
uninstall-all-oci: check-helmfile-env ## Uninstall all OCI components
helmfile -f helmfile/helmfile.yaml.gotmpl -e $(HELMFILE_ENV) destroy

# ==== CI Targets ====
# ci-dry-run: validation on terraform and helm plugins and maestro helm chart
# ci-test: Run terraform install + maestro install + health check on maestro
Expand Down
25 changes: 25 additions & 0 deletions env.oci
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# OCI/OKE Installation Configuration
RABBITMQ_URL ?= "amqp://guest:guest@rabbitmq:5672"
API_SERVICE_TYPE ?= ClusterIP
API_BASE_URL ?= http://hyperfleet-api:8000

# Container Registry Configuration
REGISTRY ?= quay.io
API_REPOSITORY ?= openshift-hyperfleet/hyperfleet-api
SENTINEL_REPOSITORY ?= openshift-hyperfleet/hyperfleet-sentinel
ADAPTER_REPOSITORY ?= openshift-hyperfleet/hyperfleet-adapter

# Helm Charts
CHART_ORG ?= openshift-hyperfleet
API_CHART_REF ?= v0.3.0
SENTINEL_CHART_REF ?= v0.3.0
ADAPTER_CHART_REF ?= v0.3.0

# Image Tags
API_IMAGE_TAG ?= v0.3.0
SENTINEL_IMAGE_TAG ?= v0.3.0
ADAPTER_IMAGE_TAG ?= v0.3.0
IMAGE_PULL_POLICY ?= Always

# Kubernetes Namespaces
NAMESPACE ?= hyperfleet
11 changes: 11 additions & 0 deletions helm/adapter-hypershift-nodepool/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v2
name: adapter-hypershift-nodepool
description: HyperShift NodePool adapter - creates NodePool resources on a remote management cluster
type: application
version: 0.1.0
appVersion: "0.0.0-dev"

dependencies:
- name: hyperfleet-adapter
version: "2.0.0"
repository: "git+https://github.com/openshift-hyperfleet/hyperfleet-adapter@charts?ref=main"
26 changes: 26 additions & 0 deletions helm/adapter-hypershift-nodepool/adapter-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# HyperShift NodePool adapter deployment configuration
# Creates NodePool resources on a remote HyperShift management cluster
adapter:
name: adapter-hypershift-nodepool
version: "0.2.0"

debug_config: true
log:
level: debug

clients:
hyperfleet_api:
base_url: http://hyperfleet-api:8000
version: v1
timeout: 10s
retry_attempts: 3
retry_backoff: exponential

broker:
subscription_id: "adapter-hypershift-nodepool"
topic: "hyperfleet-nodepools"

kubernetes:
api_version: "v1"
# Use the mounted kubeconfig to target the remote HyperShift management cluster
kube_config_path: /etc/hypershift/kubeconfig
214 changes: 214 additions & 0 deletions helm/adapter-hypershift-nodepool/adapter-task-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# HyperShift NodePool adapter task configuration
# Creates a NodePool resource on the remote management cluster
params:

- name: "nodepoolId"
source: "event.id"
type: "string"
required: true

- name: "clusterId"
source: "event.owner_references.id"
type: "string"
required: true

- name: "generation"
source: "event.generation"
type: "int"
required: true
Comment thread
vkareh marked this conversation as resolved.

- name: "namespace"
source: "env.CLUSTERS_NAMESPACE"
type: "string"

- name: "ociAD"
source: "env.OCI_AD"
type: "string"

- name: "ociSubnetId"
source: "env.OCI_SUBNET_ID"
type: "string"

- name: "ociShape"
source: "env.OCI_SHAPE"
type: "string"

- name: "ociOcpus"
source: "env.OCI_OCPUS"
type: "string"

- name: "ociMemoryGBs"
source: "env.OCI_MEMORY_GBS"
type: "string"

- name: "ociBootVolumeGB"
source: "env.OCI_BOOT_VOLUME_GB"
type: "string"

# Preconditions: look up nodepool and parent cluster from the API
preconditions:

# Fetch nodepool details (name, spec, status)
- name: "nodepoolDetails"
api_call:
method: "GET"
url: "/clusters/{{ .clusterId }}/nodepools/{{ .nodepoolId }}"
timeout: 10s
retry_attempts: 3
retry_backoff: "exponential"
capture:
- name: "nodepoolName"
field: "name"
- name: "generation"
field: "generation"
- name: "nodepoolSpec"
field: "spec"
- name: "nodepoolNotReady"
expression: |
!has(status) || !has(status.conditions)
? true
: (status.conditions.filter(c, c.type == "Ready").size() > 0
? status.conditions.filter(c, c.type == "Ready")[0].status != "True"
: true)

# Fetch parent cluster details (need the cluster name for clusterName ref)
- name: "clusterDetails"
api_call:
method: "GET"
url: "/clusters/{{ .clusterId }}"
timeout: 10s
retry_attempts: 3
retry_backoff: "exponential"
capture:
- name: "clusterName"
field: "name"

# Check if HostedCluster is Available via adapter-hypershift status
- name: "clusterAdapterStatus"
api_call:
method: "GET"
url: "/clusters/{{ .clusterId }}/statuses"
timeout: 10s
retry_attempts: 3
retry_backoff: "exponential"
capture:
- name: "clusterAvailable"
expression: |
items.filter(s, s.adapter == "adapter-hypershift").size() > 0
? (has(items.filter(s, s.adapter == "adapter-hypershift")[0].conditions)
? (items.filter(s, s.adapter == "adapter-hypershift")[0].conditions.filter(c, c.type == "Available").size() > 0
? items.filter(s, s.adapter == "adapter-hypershift")[0].conditions.filter(c, c.type == "Available")[0].status == "True"
: false)
: false)
: false

- name: "validationCheck"
# Only proceed if nodepool is NOT Ready AND HostedCluster adapter reports Available
expression: |
nodepoolNotReady && clusterAvailable
Comment thread
vkareh marked this conversation as resolved.

# Resources: NodePool on the remote management cluster
resources:

- name: "nodePool"
transport:
client: "kubernetes"
manifest:
apiVersion: hypershift.openshift.io/v1beta1
kind: NodePool
metadata:
name: "{{ .clusterName }}-{{ .nodepoolName }}"
namespace: "{{ .namespace }}"
labels:
hyperfleet.io/cluster-id: "{{ .clusterId }}"
hyperfleet.io/cluster-name: "{{ .clusterName }}"
hyperfleet.io/nodepool-id: "{{ .nodepoolId }}"
hyperfleet.io/nodepool-name: "{{ .nodepoolName }}"
spec:
clusterName: "{{ .clusterName }}"
replicas: {{ index .nodepoolSpec "replicas" | default 2 }}
management:
autoRepair: true
upgradeType: Replace
platform:
type: OCI
oci:
instanceShape: '{{ index .nodepoolSpec "instanceShape" | default .ociShape }}'
instanceShapeConfig:
ocpus: {{ index .nodepoolSpec "ocpus" | default .ociOcpus }}
memoryInGBs: {{ index .nodepoolSpec "memoryInGBs" | default .ociMemoryGBs }}
availabilityDomain: '{{ index .nodepoolSpec "availabilityDomain" | default .ociAD }}'
subnetId: '{{ index .nodepoolSpec "subnetId" | default .ociSubnetId }}'
bootVolumeSize: {{ index .nodepoolSpec "bootVolumeSize" | default .ociBootVolumeGB }}
release:
image: '{{ index .nodepoolSpec "releaseImage" | default "quay.io/openshift-release-dev/ocp-release:4.20.2-x86_64" }}'
discovery:
namespace: "{{ .namespace }}"
by_selectors:
label_selector:
hyperfleet.io/nodepool-id: "{{ .nodepoolId }}"

# Post-processing: report NodePool status back to API
post:
payloads:
- name: "statusPayload"
build:
adapter: "{{ .adapter.name }}"
conditions:
- type: "Applied"
status:
expression: |
has(resources.nodePool.metadata.creationTimestamp) ? "True" : "False"
reason:
expression: |
has(resources.nodePool.metadata.creationTimestamp) ? "NodePoolCreated" : "NodePoolPending"
message:
expression: |
has(resources.nodePool.metadata.creationTimestamp)
? "NodePool has been created on the management cluster"
: "NodePool is pending creation"
- type: "Available"
status:
expression: |
has(resources.nodePool.status) && has(resources.nodePool.status.conditions)
? (resources.nodePool.status.conditions.filter(c, c.type == "Ready").size() > 0
? resources.nodePool.status.conditions.filter(c, c.type == "Ready")[0].status
: "False")
: "False"
reason:
expression: |
has(resources.nodePool.status) && has(resources.nodePool.status.conditions)
? (resources.nodePool.status.conditions.filter(c, c.type == "Ready").size() > 0
? resources.nodePool.status.conditions.filter(c, c.type == "Ready")[0].reason
: "WaitingForNodes")
: "WaitingForNodes"
message:
expression: |
has(resources.nodePool.status) && has(resources.nodePool.status.conditions)
? (resources.nodePool.status.conditions.filter(c, c.type == "Ready").size() > 0
? resources.nodePool.status.conditions.filter(c, c.type == "Ready")[0].message
: "Waiting for worker nodes to be provisioned")
: "Waiting for worker nodes to be provisioned"
- type: "Health"
status:
expression: |
adapter.?executionStatus.orValue("") == "success" ? "True" : (adapter.?executionStatus.orValue("") == "failed" ? "False" : "Unknown")
reason:
expression: |
adapter.?errorReason.orValue("") != "" ? adapter.?errorReason.orValue("") : "Healthy"
message:
expression: |
adapter.?errorMessage.orValue("") != "" ? adapter.?errorMessage.orValue("") : "Adapter executed successfully"
observed_generation:
expression: "generation"
observed_time: "{{ now | date \"2006-01-02T15:04:05Z07:00\" }}"

post_actions:
- name: "reportNodepoolStatus"
api_call:
method: "PUT"
url: "/clusters/{{ .clusterId }}/nodepools/{{ .nodepoolId }}/statuses"
headers:
- name: "Content-Type"
value: "application/json"
body: "{{ .statusPayload }}"
Binary file not shown.
28 changes: 28 additions & 0 deletions helm/adapter-hypershift-nodepool/nodepool-manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: hypershift.openshift.io/v1beta1
kind: NodePool
metadata:
name: "{{ .clusterName }}-{{ .nodepoolName }}"
namespace: "{{ .namespace }}"
labels:
hyperfleet.io/cluster-id: "{{ .clusterId }}"
hyperfleet.io/cluster-name: "{{ .clusterName }}"
hyperfleet.io/nodepool-id: "{{ .nodepoolId }}"
hyperfleet.io/nodepool-name: "{{ .nodepoolName }}"
spec:
clusterName: "{{ .clusterName }}"
replicas: {{ index .nodepoolSpec "replicas" | default 2 }}
management:
autoRepair: true
upgradeType: Replace
platform:
type: OCI
oci:
instanceShape: "{{ index .nodepoolSpec "instanceShape" | default .ociShape }}"
instanceShapeConfig:
ocpus: {{ index .nodepoolSpec "ocpus" | default .ociOcpus }}
memoryInGBs: {{ index .nodepoolSpec "memoryInGBs" | default .ociMemoryGBs }}
availabilityDomain: "{{ index .nodepoolSpec "availabilityDomain" | default .ociAD }}"
subnetId: "{{ index .nodepoolSpec "subnetId" | default .ociSubnetId }}"
bootVolumeSize: {{ index .nodepoolSpec "bootVolumeSize" | default .ociBootVolumeGB }}
release:
image: "{{ index .nodepoolSpec "releaseImage" | default "quay.io/openshift-release-dev/ocp-release:4.20.2-x86_64" }}"
Comment thread
vkareh marked this conversation as resolved.
Loading