Skip to content

Commit af065ee

Browse files
committed
Add adapter-hypershift-nodepool chart and fix adapter-hypershift for OCI
Add new adapter-hypershift-nodepool Helm chart that subscribes to the nodepools topic, validates the parent HostedCluster is Available via adapter status, creates a HyperShift NodePool CR on the management cluster, and reports status back to the API. Fix adapter-hypershift task config to use Route instead of NodePort for Ignition/OAuth. Add values-oci.yaml for sentinel-nodepools with RabbitMQ config. Pin sentinel-nodepools Chart.yaml dependency to v0.2.0.
1 parent be23e58 commit af065ee

9 files changed

Lines changed: 363 additions & 9 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: v2
2+
name: adapter-hypershift-nodepool
3+
description: HyperShift NodePool adapter - creates NodePool resources on a remote management cluster
4+
type: application
5+
version: 0.1.0
6+
appVersion: "0.0.0-dev"
7+
8+
dependencies:
9+
- name: hyperfleet-adapter
10+
version: "2.0.0"
11+
repository: "git+https://github.com/openshift-hyperfleet/hyperfleet-adapter@charts?ref=main"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# HyperShift NodePool adapter deployment configuration
2+
# Creates NodePool resources on a remote HyperShift management cluster
3+
adapter:
4+
name: adapter-hypershift-nodepool
5+
version: "0.2.0"
6+
7+
debug_config: true
8+
log:
9+
level: debug
10+
11+
clients:
12+
hyperfleet_api:
13+
base_url: http://hyperfleet-api:8000
14+
version: v1
15+
timeout: 10s
16+
retry_attempts: 3
17+
retry_backoff: exponential
18+
19+
broker:
20+
subscription_id: "adapter-hypershift-nodepool"
21+
topic: "hyperfleet-nodepools"
22+
23+
kubernetes:
24+
api_version: "v1"
25+
# Use the mounted kubeconfig to target the remote HyperShift management cluster
26+
kube_config_path: /etc/hypershift/kubeconfig
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# HyperShift NodePool adapter task configuration
2+
# Creates a NodePool resource on the remote management cluster
3+
params:
4+
5+
- name: "nodepoolId"
6+
source: "event.id"
7+
type: "string"
8+
required: true
9+
10+
- name: "clusterId"
11+
source: "event.owner_references.id"
12+
type: "string"
13+
required: true
14+
15+
- name: "generation"
16+
source: "event.generation"
17+
type: "int"
18+
required: true
19+
20+
- name: "namespace"
21+
source: "env.CLUSTERS_NAMESPACE"
22+
type: "string"
23+
24+
- name: "ociAD"
25+
source: "env.OCI_AD"
26+
type: "string"
27+
28+
- name: "ociSubnetId"
29+
source: "env.OCI_SUBNET_ID"
30+
type: "string"
31+
32+
- name: "ociShape"
33+
source: "env.OCI_SHAPE"
34+
type: "string"
35+
36+
- name: "ociOcpus"
37+
source: "env.OCI_OCPUS"
38+
type: "string"
39+
40+
- name: "ociMemoryGBs"
41+
source: "env.OCI_MEMORY_GBS"
42+
type: "string"
43+
44+
- name: "ociBootVolumeGB"
45+
source: "env.OCI_BOOT_VOLUME_GB"
46+
type: "string"
47+
48+
# Preconditions: look up nodepool and parent cluster from the API
49+
preconditions:
50+
51+
# Fetch nodepool details (name, spec, status)
52+
- name: "nodepoolDetails"
53+
api_call:
54+
method: "GET"
55+
url: "/clusters/{{ .clusterId }}/nodepools/{{ .nodepoolId }}"
56+
timeout: 10s
57+
retry_attempts: 3
58+
retry_backoff: "exponential"
59+
capture:
60+
- name: "nodepoolName"
61+
field: "name"
62+
- name: "generation"
63+
field: "generation"
64+
- name: "nodepoolSpec"
65+
field: "spec"
66+
- name: "nodepoolNotReady"
67+
expression: |
68+
status.conditions.filter(c, c.type == "Ready").size() > 0
69+
? status.conditions.filter(c, c.type == "Ready")[0].status != "True"
70+
: true
71+
72+
# Fetch parent cluster details (need the cluster name for clusterName ref)
73+
- name: "clusterDetails"
74+
api_call:
75+
method: "GET"
76+
url: "/clusters/{{ .clusterId }}"
77+
timeout: 10s
78+
retry_attempts: 3
79+
retry_backoff: "exponential"
80+
capture:
81+
- name: "clusterName"
82+
field: "name"
83+
84+
# Check if HostedCluster is Available via adapter-hypershift status
85+
- name: "clusterAdapterStatus"
86+
api_call:
87+
method: "GET"
88+
url: "/clusters/{{ .clusterId }}/statuses"
89+
timeout: 10s
90+
retry_attempts: 3
91+
retry_backoff: "exponential"
92+
capture:
93+
- name: "clusterAvailable"
94+
expression: |
95+
items.filter(s, s.adapter == "adapter-hypershift").size() > 0 ? (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
96+
97+
- name: "validationCheck"
98+
# Only proceed if nodepool is NOT Ready AND HostedCluster adapter reports Available
99+
expression: |
100+
nodepoolNotReady && clusterAvailable
101+
102+
# Resources: NodePool on the remote management cluster
103+
resources:
104+
105+
- name: "nodePool"
106+
transport:
107+
client: "kubernetes"
108+
manifest:
109+
apiVersion: hypershift.openshift.io/v1beta1
110+
kind: NodePool
111+
metadata:
112+
name: "{{ .clusterName }}-{{ .nodepoolName }}"
113+
namespace: "{{ .namespace }}"
114+
labels:
115+
hyperfleet.io/cluster-id: "{{ .clusterId }}"
116+
hyperfleet.io/cluster-name: "{{ .clusterName }}"
117+
hyperfleet.io/nodepool-id: "{{ .nodepoolId }}"
118+
hyperfleet.io/nodepool-name: "{{ .nodepoolName }}"
119+
spec:
120+
clusterName: "{{ .clusterName }}"
121+
replicas: 2
122+
management:
123+
autoRepair: true
124+
upgradeType: Replace
125+
platform:
126+
type: OCI
127+
oci:
128+
instanceShape: "{{ .ociShape }}"
129+
instanceShapeConfig:
130+
ocpus: 4
131+
memoryInGBs: 16
132+
availabilityDomain: "{{ .ociAD }}"
133+
subnetId: "{{ .ociSubnetId }}"
134+
bootVolumeSize: 120
135+
release:
136+
image: "quay.io/openshift-release-dev/ocp-release:4.20.2-x86_64"
137+
discovery:
138+
namespace: "{{ .namespace }}"
139+
by_selectors:
140+
label_selector:
141+
hyperfleet.io/nodepool-id: "{{ .nodepoolId }}"
142+
143+
# Post-processing: report NodePool status back to API
144+
post:
145+
payloads:
146+
- name: "statusPayload"
147+
build:
148+
adapter: "{{ .adapter.name }}"
149+
conditions:
150+
- type: "Applied"
151+
status:
152+
expression: |
153+
has(resources.nodePool.metadata.creationTimestamp) ? "True" : "False"
154+
reason:
155+
expression: |
156+
has(resources.nodePool.metadata.creationTimestamp) ? "NodePoolCreated" : "NodePoolPending"
157+
message:
158+
expression: |
159+
has(resources.nodePool.metadata.creationTimestamp)
160+
? "NodePool has been created on the management cluster"
161+
: "NodePool is pending creation"
162+
- type: "Available"
163+
status:
164+
expression: |
165+
has(resources.nodePool.status) && has(resources.nodePool.status.conditions)
166+
? (resources.nodePool.status.conditions.filter(c, c.type == "Ready").size() > 0
167+
? resources.nodePool.status.conditions.filter(c, c.type == "Ready")[0].status
168+
: "False")
169+
: "False"
170+
reason:
171+
expression: |
172+
has(resources.nodePool.status) && has(resources.nodePool.status.conditions)
173+
? (resources.nodePool.status.conditions.filter(c, c.type == "Ready").size() > 0
174+
? resources.nodePool.status.conditions.filter(c, c.type == "Ready")[0].reason
175+
: "WaitingForNodes")
176+
: "WaitingForNodes"
177+
message:
178+
expression: |
179+
has(resources.nodePool.status) && has(resources.nodePool.status.conditions)
180+
? (resources.nodePool.status.conditions.filter(c, c.type == "Ready").size() > 0
181+
? resources.nodePool.status.conditions.filter(c, c.type == "Ready")[0].message
182+
: "Waiting for worker nodes to be provisioned")
183+
: "Waiting for worker nodes to be provisioned"
184+
- type: "Health"
185+
status:
186+
expression: |
187+
adapter.?executionStatus.orValue("") == "success" ? "True" : (adapter.?executionStatus.orValue("") == "failed" ? "False" : "Unknown")
188+
reason:
189+
expression: |
190+
adapter.?errorReason.orValue("") != "" ? adapter.?errorReason.orValue("") : "Healthy"
191+
message:
192+
expression: |
193+
adapter.?errorMessage.orValue("") != "" ? adapter.?errorMessage.orValue("") : "Adapter executed successfully"
194+
observed_generation:
195+
expression: "generation"
196+
observed_time: "{{ now | date \"2006-01-02T15:04:05Z07:00\" }}"
197+
198+
post_actions:
199+
- name: "reportNodepoolStatus"
200+
api_call:
201+
method: "POST"
202+
url: "/clusters/{{ .clusterId }}/nodepools/{{ .nodepoolId }}/statuses"
203+
headers:
204+
- name: "Content-Type"
205+
value: "application/json"
206+
body: "{{ .statusPayload }}"
Binary file not shown.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
apiVersion: hypershift.openshift.io/v1beta1
2+
kind: NodePool
3+
metadata:
4+
name: "{{ .clusterName }}-{{ .nodepoolName }}"
5+
namespace: "{{ .namespace }}"
6+
labels:
7+
hyperfleet.io/cluster-id: "{{ .clusterId }}"
8+
hyperfleet.io/cluster-name: "{{ .clusterName }}"
9+
hyperfleet.io/nodepool-id: "{{ .nodepoolId }}"
10+
hyperfleet.io/nodepool-name: "{{ .nodepoolName }}"
11+
spec:
12+
clusterName: "{{ .clusterName }}"
13+
replicas: {{ index .nodepoolSpec "replicas" | default 2 }}
14+
management:
15+
autoRepair: true
16+
upgradeType: Replace
17+
platform:
18+
type: OCI
19+
oci:
20+
instanceShape: "{{ index .nodepoolSpec "instanceShape" | default .ociShape }}"
21+
instanceShapeConfig:
22+
ocpus: {{ index .nodepoolSpec "ocpus" | default .ociOcpus }}
23+
memoryInGBs: {{ index .nodepoolSpec "memoryInGBs" | default .ociMemoryGBs }}
24+
availabilityDomain: "{{ index .nodepoolSpec "availabilityDomain" | default .ociAD }}"
25+
subnetId: "{{ index .nodepoolSpec "subnetId" | default .ociSubnetId }}"
26+
bootVolumeSize: {{ index .nodepoolSpec "bootVolumeSize" | default .ociBootVolumeGB }}
27+
release:
28+
image: "{{ index .nodepoolSpec "releaseImage" | default "quay.io/openshift-release-dev/ocp-release:4.20.2-x86_64" }}"
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Values for adapter-hypershift-nodepool
2+
# Creates NodePool resources on a remote HyperShift management cluster
3+
4+
hyperfleet-adapter:
5+
image:
6+
registry: CHANGE_ME
7+
repository: CHANGE_ME
8+
tag: latest
9+
10+
adapterConfig:
11+
create: true
12+
log:
13+
level: debug
14+
15+
adapterTaskConfig:
16+
create: true
17+
18+
broker:
19+
type: googlepubsub
20+
googlepubsub:
21+
projectId: CHANGE_ME
22+
subscriptionId: CHANGE_ME
23+
topic: CHANGE_ME
24+
deadLetterTopic: ""
25+
createTopicIfMissing: true
26+
createSubscriptionIfMissing: true
27+
rabbitmq:
28+
url: CHANGE_ME
29+
queue: ""
30+
exchange: ""
31+
routingKey: ""
32+
33+
env:
34+
- name: NAMESPACE
35+
valueFrom:
36+
fieldRef:
37+
fieldPath: metadata.namespace
38+
- name: CLUSTERS_NAMESPACE
39+
value: clusters
40+
- name: OCI_AD
41+
value: US-SANJOSE-1-AD-1
42+
- name: OCI_SUBNET_ID
43+
value: CHANGE_ME
44+
- name: OCI_SHAPE
45+
value: VM.Standard.E4.Flex
46+
- name: OCI_OCPUS
47+
value: "4"
48+
- name: OCI_MEMORY_GBS
49+
value: "16"
50+
- name: OCI_BOOT_VOLUME_GB
51+
value: "120"
52+
53+
# Mount the management cluster kubeconfig
54+
extraVolumeMounts:
55+
- name: hypershift-kubeconfig
56+
mountPath: /etc/hypershift
57+
readOnly: true
58+
59+
extraVolumes:
60+
- name: hypershift-kubeconfig
61+
secret:
62+
secretName: hypershift-mgmt-kubeconfig
63+
64+
# RBAC is for the local CLM cluster only; remote access uses the mounted kubeconfig
65+
rbac:
66+
resources:
67+
- configmaps

helm/adapter-hypershift/adapter-task-config.yaml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ params:
3636
source: "env.CPO_IMAGE"
3737
type: "string"
3838

39-
- name: "workerNodeIP"
40-
source: "env.WORKER_NODE_IP"
41-
type: "string"
4239

4340
# Preconditions: check cluster details from API
4441
preconditions:
@@ -118,14 +115,10 @@ resources:
118115
services:
119116
- service: Ignition
120117
servicePublishingStrategy:
121-
type: NodePort
122-
nodePort:
123-
address: "{{ .workerNodeIP }}"
118+
type: Route
124119
- service: OAuthServer
125120
servicePublishingStrategy:
126-
type: NodePort
127-
nodePort:
128-
address: "{{ .workerNodeIP }}"
121+
type: Route
129122
- service: APIServer
130123
servicePublishingStrategy:
131124
type: LoadBalancer
0 Bytes
Binary file not shown.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# OCI/OKE overrides for Sentinel nodepools (v0.2.0 config format)
2+
3+
hyperfleet-sentinel:
4+
config:
5+
resourceType: nodepools
6+
resourceSelector: []
7+
8+
hyperfleetApi:
9+
baseUrl: http://hyperfleet-api:8000
10+
timeout: 5s
11+
12+
broker:
13+
type: rabbitmq
14+
topic: hyperfleet-nodepools
15+
rabbitmq:
16+
url: amqp://guest:guest@rabbitmq:5672/
17+
exchangeType: topic
18+
19+
monitoring:
20+
podMonitoring:
21+
enabled: false
22+
prometheusRule:
23+
enabled: false

0 commit comments

Comments
 (0)