Unverified Commit a82f350a authored by julienmancuso's avatar julienmancuso Committed by GitHub
Browse files

feat: remove dynamoComponentRequest CRD (#856)

parent c544e8ec
...@@ -26,10 +26,24 @@ spec: ...@@ -26,10 +26,24 @@ spec:
kind: DynamoComponent kind: DynamoComponent
listKind: DynamoComponentList listKind: DynamoComponentList
plural: dynamocomponents plural: dynamocomponents
shortNames:
- dc
singular: dynamocomponent singular: dynamocomponent
scope: Namespaced scope: Namespaced
versions: versions:
- name: v1alpha1 - additionalPrinterColumns:
- description: Dynamo component
jsonPath: .spec.dynamoComponent
name: DynamoComponent
type: string
- description: Image Exists
jsonPath: .status.conditions[?(@.type=='ImageExists')].status
name: Image-Exists
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1alpha1
schema: schema:
openAPIV3Schema: openAPIV3Schema:
properties: properties:
...@@ -41,10 +55,1358 @@ spec: ...@@ -41,10 +55,1358 @@ spec:
type: object type: object
spec: spec:
properties: properties:
buildArgs:
items:
type: string
type: array
dockerConfigJsonSecretName:
type: string
downloadUrl:
type: string
downloaderContainerEnvFrom:
items:
properties:
configMapRef:
properties:
name:
default: ""
type: string
optional:
type: boolean
type: object
x-kubernetes-map-type: atomic
prefix:
type: string
secretRef:
properties:
name:
default: ""
type: string
optional:
type: boolean
type: object
x-kubernetes-map-type: atomic
type: object
type: array
dynamoComponent: dynamoComponent:
type: string type: string
image: image:
type: string type: string
imageBuildTimeout:
format: int64
type: integer
imageBuilderContainerResources:
properties:
claims:
items:
properties:
name:
type: string
request:
type: string
required:
- name
type: object
type: array
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
limits:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
type: object
requests:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
type: object
type: object
imageBuilderExtraContainerEnv:
items:
properties:
name:
type: string
value:
type: string
valueFrom:
properties:
configMapKeyRef:
properties:
key:
type: string
name:
default: ""
type: string
optional:
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
fieldRef:
properties:
apiVersion:
type: string
fieldPath:
type: string
required:
- fieldPath
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
properties:
containerName:
type: string
divisor:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
type: string
required:
- resource
type: object
x-kubernetes-map-type: atomic
secretKeyRef:
properties:
key:
type: string
name:
default: ""
type: string
optional:
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
required:
- name
type: object
type: array
imageBuilderExtraPodMetadata:
properties:
annotations:
additionalProperties:
type: string
type: object
labels:
additionalProperties:
type: string
type: object
type: object
imageBuilderExtraPodSpec:
properties:
affinity:
properties:
nodeAffinity:
properties:
preferredDuringSchedulingIgnoredDuringExecution:
items:
properties:
preference:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchFields:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
type: object
x-kubernetes-map-type: atomic
weight:
format: int32
type: integer
required:
- preference
- weight
type: object
type: array
x-kubernetes-list-type: atomic
requiredDuringSchedulingIgnoredDuringExecution:
properties:
nodeSelectorTerms:
items:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchFields:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
type: object
x-kubernetes-map-type: atomic
type: array
x-kubernetes-list-type: atomic
required:
- nodeSelectorTerms
type: object
x-kubernetes-map-type: atomic
type: object
podAffinity:
properties:
preferredDuringSchedulingIgnoredDuringExecution:
items:
properties:
podAffinityTerm:
properties:
labelSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
type: string
required:
- topologyKey
type: object
weight:
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
x-kubernetes-list-type: atomic
requiredDuringSchedulingIgnoredDuringExecution:
items:
properties:
labelSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
type: string
required:
- topologyKey
type: object
type: array
x-kubernetes-list-type: atomic
type: object
podAntiAffinity:
properties:
preferredDuringSchedulingIgnoredDuringExecution:
items:
properties:
podAffinityTerm:
properties:
labelSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
type: string
required:
- topologyKey
type: object
weight:
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
x-kubernetes-list-type: atomic
requiredDuringSchedulingIgnoredDuringExecution:
items:
properties:
labelSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
type: string
required:
- topologyKey
type: object
type: array
x-kubernetes-list-type: atomic
type: object
type: object
containers:
items:
properties:
args:
items:
type: string
type: array
x-kubernetes-list-type: atomic
command:
items:
type: string
type: array
x-kubernetes-list-type: atomic
env:
items:
properties:
name:
type: string
value:
type: string
valueFrom:
properties:
configMapKeyRef:
properties:
key:
type: string
name:
default: ""
type: string
optional:
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
fieldRef:
properties:
apiVersion:
type: string
fieldPath:
type: string
required:
- fieldPath
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
properties:
containerName:
type: string
divisor:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
type: string
required:
- resource
type: object
x-kubernetes-map-type: atomic
secretKeyRef:
properties:
key:
type: string
name:
default: ""
type: string
optional:
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
required:
- name
type: object
type: array
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
envFrom:
items:
properties:
configMapRef:
properties:
name:
default: ""
type: string
optional:
type: boolean
type: object
x-kubernetes-map-type: atomic
prefix:
type: string
secretRef:
properties:
name:
default: ""
type: string
optional:
type: boolean
type: object
x-kubernetes-map-type: atomic
type: object
type: array
x-kubernetes-list-type: atomic
image:
type: string
imagePullPolicy:
type: string
lifecycle:
properties:
postStart:
properties:
exec:
properties:
command:
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
httpGet:
properties:
host:
type: string
httpHeaders:
items:
properties:
name:
type: string
value:
type: string
required:
- name
- value
type: object
type: array
x-kubernetes-list-type: atomic
path:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
scheme:
type: string
required:
- port
type: object
sleep:
properties:
seconds:
format: int64
type: integer
required:
- seconds
type: object
tcpSocket:
properties:
host:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
required:
- port
type: object
type: object
preStop:
properties:
exec:
properties:
command:
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
httpGet:
properties:
host:
type: string
httpHeaders:
items:
properties:
name:
type: string
value:
type: string
required:
- name
- value
type: object
type: array
x-kubernetes-list-type: atomic
path:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
scheme:
type: string
required:
- port
type: object
sleep:
properties:
seconds:
format: int64
type: integer
required:
- seconds
type: object
tcpSocket:
properties:
host:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
required:
- port
type: object
type: object
type: object
livenessProbe:
properties:
exec:
properties:
command:
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
failureThreshold:
format: int32
type: integer
grpc:
properties:
port:
format: int32
type: integer
service:
default: ""
type: string
required:
- port
type: object
httpGet:
properties:
host:
type: string
httpHeaders:
items:
properties:
name:
type: string
value:
type: string
required:
- name
- value
type: object
type: array
x-kubernetes-list-type: atomic
path:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
scheme:
type: string
required:
- port
type: object
initialDelaySeconds:
format: int32
type: integer
periodSeconds:
format: int32
type: integer
successThreshold:
format: int32
type: integer
tcpSocket:
properties:
host:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
required:
- port
type: object
terminationGracePeriodSeconds:
format: int64
type: integer
timeoutSeconds:
format: int32
type: integer
type: object
name:
type: string
ports:
items:
properties:
containerPort:
format: int32
type: integer
hostIP:
type: string
hostPort:
format: int32
type: integer
name:
type: string
protocol:
default: TCP
type: string
required:
- containerPort
type: object
type: array
x-kubernetes-list-map-keys:
- containerPort
- protocol
x-kubernetes-list-type: map
readinessProbe:
properties:
exec:
properties:
command:
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
failureThreshold:
format: int32
type: integer
grpc:
properties:
port:
format: int32
type: integer
service:
default: ""
type: string
required:
- port
type: object
httpGet:
properties:
host:
type: string
httpHeaders:
items:
properties:
name:
type: string
value:
type: string
required:
- name
- value
type: object
type: array
x-kubernetes-list-type: atomic
path:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
scheme:
type: string
required:
- port
type: object
initialDelaySeconds:
format: int32
type: integer
periodSeconds:
format: int32
type: integer
successThreshold:
format: int32
type: integer
tcpSocket:
properties:
host:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
required:
- port
type: object
terminationGracePeriodSeconds:
format: int64
type: integer
timeoutSeconds:
format: int32
type: integer
type: object
resizePolicy:
items:
properties:
resourceName:
type: string
restartPolicy:
type: string
required:
- resourceName
- restartPolicy
type: object
type: array
x-kubernetes-list-type: atomic
resources:
properties:
claims:
items:
properties:
name:
type: string
request:
type: string
required:
- name
type: object
type: array
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
limits:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
type: object
requests:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
type: object
type: object
restartPolicy:
type: string
securityContext:
properties:
allowPrivilegeEscalation:
type: boolean
appArmorProfile:
properties:
localhostProfile:
type: string
type:
type: string
required:
- type
type: object
capabilities:
properties:
add:
items:
type: string
type: array
x-kubernetes-list-type: atomic
drop:
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
privileged:
type: boolean
procMount:
type: string
readOnlyRootFilesystem:
type: boolean
runAsGroup:
format: int64
type: integer
runAsNonRoot:
type: boolean
runAsUser:
format: int64
type: integer
seLinuxOptions:
properties:
level:
type: string
role:
type: string
type:
type: string
user:
type: string
type: object
seccompProfile:
properties:
localhostProfile:
type: string
type:
type: string
required:
- type
type: object
windowsOptions:
properties:
gmsaCredentialSpec:
type: string
gmsaCredentialSpecName:
type: string
hostProcess:
type: boolean
runAsUserName:
type: string
type: object
type: object
startupProbe:
properties:
exec:
properties:
command:
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
failureThreshold:
format: int32
type: integer
grpc:
properties:
port:
format: int32
type: integer
service:
default: ""
type: string
required:
- port
type: object
httpGet:
properties:
host:
type: string
httpHeaders:
items:
properties:
name:
type: string
value:
type: string
required:
- name
- value
type: object
type: array
x-kubernetes-list-type: atomic
path:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
scheme:
type: string
required:
- port
type: object
initialDelaySeconds:
format: int32
type: integer
periodSeconds:
format: int32
type: integer
successThreshold:
format: int32
type: integer
tcpSocket:
properties:
host:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
required:
- port
type: object
terminationGracePeriodSeconds:
format: int64
type: integer
timeoutSeconds:
format: int32
type: integer
type: object
stdin:
type: boolean
stdinOnce:
type: boolean
terminationMessagePath:
type: string
terminationMessagePolicy:
type: string
tty:
type: boolean
volumeDevices:
items:
properties:
devicePath:
type: string
name:
type: string
required:
- devicePath
- name
type: object
type: array
x-kubernetes-list-map-keys:
- devicePath
x-kubernetes-list-type: map
volumeMounts:
items:
properties:
mountPath:
type: string
mountPropagation:
type: string
name:
type: string
readOnly:
type: boolean
recursiveReadOnly:
type: string
subPath:
type: string
subPathExpr:
type: string
required:
- mountPath
- name
type: object
type: array
x-kubernetes-list-map-keys:
- mountPath
x-kubernetes-list-type: map
workingDir:
type: string
required:
- name
type: object
type: array
nodeSelector:
additionalProperties:
type: string
type: object
priorityClassName:
type: string
schedulerName:
type: string
serviceAccountName:
type: string
tolerations:
items:
properties:
effect:
type: string
key:
type: string
operator:
type: string
tolerationSeconds:
format: int64
type: integer
value:
type: string
type: object
type: array
topologySpreadConstraints:
items:
properties:
labelSelector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
items:
type: string
type: array
x-kubernetes-list-type: atomic
maxSkew:
format: int32
type: integer
minDomains:
format: int32
type: integer
nodeAffinityPolicy:
type: string
nodeTaintsPolicy:
type: string
topologyKey:
type: string
whenUnsatisfiable:
type: string
required:
- maxSkew
- topologyKey
- whenUnsatisfiable
type: object
type: array
type: object
imagePullSecrets: imagePullSecrets:
items: items:
properties: properties:
...@@ -58,14 +1420,47 @@ spec: ...@@ -58,14 +1420,47 @@ spec:
type: string type: string
required: required:
- dynamoComponent - dynamoComponent
- image
type: object type: object
status: status:
properties: properties:
ready: conditions:
type: boolean items:
properties:
lastTransitionTime:
format: date-time
type: string
message:
maxLength: 32768
type: string
observedGeneration:
format: int64
minimum: 0
type: integer
reason:
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
enum:
- "True"
- "False"
- Unknown
type: string
type:
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
required: required:
- ready - conditions
type: object type: object
type: object type: object
served: true served: true
......
...@@ -26,6 +26,8 @@ spec: ...@@ -26,6 +26,8 @@ spec:
kind: DynamoGraphDeployment kind: DynamoGraphDeployment
listKind: DynamoGraphDeploymentList listKind: DynamoGraphDeploymentList
plural: dynamographdeployments plural: dynamographdeployments
shortNames:
- dgd
singular: dynamographdeployment singular: dynamographdeployment
scope: Namespaced scope: Namespaced
versions: versions:
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
# It should be run by config/default # It should be run by config/default
resources: resources:
- bases/nvidia.com_dynamocomponentdeployments.yaml - bases/nvidia.com_dynamocomponentdeployments.yaml
- bases/nvidia.com_dynamocomponentrequests.yaml
- bases/nvidia.com_dynamocomponents.yaml - bases/nvidia.com_dynamocomponents.yaml
- bases/nvidia.com_dynamographdeployments.yaml - bases/nvidia.com_dynamographdeployments.yaml
#+kubebuilder:scaffold:crdkustomizeresource #+kubebuilder:scaffold:crdkustomizeresource
...@@ -31,7 +30,6 @@ patches: [] ...@@ -31,7 +30,6 @@ patches: []
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
# patches here are for enabling the CA injection for each CRD # patches here are for enabling the CA injection for each CRD
#- path: patches/cainjection_in_dynamocomponentdeployments.yaml #- path: patches/cainjection_in_dynamocomponentdeployments.yaml
#- path: patches/cainjection_in_dynamocomponentrequests.yaml
#- path: patches/cainjection_in_dynamocomponents.yaml #- path: patches/cainjection_in_dynamocomponents.yaml
#+kubebuilder:scaffold:crdkustomizecainjectionpatch #+kubebuilder:scaffold:crdkustomizecainjectionpatch
......
...@@ -37,8 +37,8 @@ resources: ...@@ -37,8 +37,8 @@ resources:
# if you do not want those helpers be installed with your Project. # if you do not want those helpers be installed with your Project.
# - dynamocomponent_editor_role.yaml # - dynamocomponent_editor_role.yaml
# - dynamocomponent_viewer_role.yaml # - dynamocomponent_viewer_role.yaml
# - dynamocomponentrequest_editor_role.yaml # - dynamocomponent_editor_role.yaml
# - dynamocomponentrequest_viewer_role.yaml # - dynamocomponent_viewer_role.yaml
# - dynamocomponentdeployment_editor_role.yaml # - dynamocomponentdeployment_editor_role.yaml
# - dynamocomponentdeployment_viewer_role.yaml # - dynamocomponentdeployment_viewer_role.yaml
...@@ -129,7 +129,6 @@ rules: ...@@ -129,7 +129,6 @@ rules:
- nvidia.com - nvidia.com
resources: resources:
- dynamocomponentdeployments - dynamocomponentdeployments
- dynamocomponentrequests
- dynamocomponents - dynamocomponents
- dynamographdeployments - dynamographdeployments
verbs: verbs:
...@@ -144,7 +143,7 @@ rules: ...@@ -144,7 +143,7 @@ rules:
- nvidia.com - nvidia.com
resources: resources:
- dynamocomponentdeployments/finalizers - dynamocomponentdeployments/finalizers
- dynamocomponentrequests/finalizers - dynamocomponents/finalizers
- dynamographdeployments/finalizers - dynamographdeployments/finalizers
verbs: verbs:
- update - update
...@@ -152,7 +151,6 @@ rules: ...@@ -152,7 +151,6 @@ rules:
- nvidia.com - nvidia.com
resources: resources:
- dynamocomponentdeployments/status - dynamocomponentdeployments/status
- dynamocomponentrequests/status
- dynamocomponents/status - dynamocomponents/status
- dynamographdeployments/status - dynamographdeployments/status
verbs: verbs:
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
## Append samples of your project ## ## Append samples of your project ##
resources: resources:
- nvidia.com_v1alpha1_dynamocomponentdeployment.yaml - nvidia.com_v1alpha1_dynamocomponentdeployment.yaml
- nvidia.com_v1alpha1_dynamocomponentrequest.yaml
- nvidia.com_v1alpha1_dynamocomponent.yaml - nvidia.com_v1alpha1_dynamocomponent.yaml
- nvidia.com_v1alpha1_dynamographdeployment.yaml - nvidia.com_v1alpha1_dynamographdeployment.yaml
#+kubebuilder:scaffold:manifestskustomizesamples #+kubebuilder:scaffold:manifestskustomizesamples
...@@ -31,21 +31,17 @@ func GetDynamoImageBuilderNamespace(ctx context.Context) (namespace string, err ...@@ -31,21 +31,17 @@ func GetDynamoImageBuilderNamespace(ctx context.Context) (namespace string, err
type DockerRegistryConfig struct { type DockerRegistryConfig struct {
DynamoComponentsRepositoryName string `yaml:"dynamo_components_repository_name"` DynamoComponentsRepositoryName string `yaml:"dynamo_components_repository_name"`
Server string `yaml:"server"` Server string `yaml:"server"`
InClusterServer string `yaml:"in_cluster_server"` SecretName string `yaml:"secret_name"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Secure bool `yaml:"secure"` Secure bool `yaml:"secure"`
} }
func GetDockerRegistryConfig() (conf *DockerRegistryConfig, err error) { func GetDockerRegistryConfig() *DockerRegistryConfig {
return &DockerRegistryConfig{ return &DockerRegistryConfig{
DynamoComponentsRepositoryName: os.Getenv(consts.EnvDockerRegistryDynamoComponentsRepositoryName), DynamoComponentsRepositoryName: os.Getenv(consts.EnvDockerRegistryDynamoComponentsRepositoryName),
Server: os.Getenv(consts.EnvDockerRegistryServer), Server: os.Getenv(consts.EnvDockerRegistryServer),
InClusterServer: os.Getenv(consts.EnvDockerRegistryInClusterServer), SecretName: os.Getenv(consts.EnvDockerRegistrySecret),
Username: os.Getenv(consts.EnvDockerRegistryUsername),
Password: os.Getenv(consts.EnvDockerRegistryPassword),
Secure: os.Getenv(consts.EnvDockerRegistrySecure) == "true", Secure: os.Getenv(consts.EnvDockerRegistrySecure) == "true",
}, nil }
} }
type ApiStoreConfig struct { type ApiStoreConfig struct {
......
...@@ -26,11 +26,8 @@ const ( ...@@ -26,11 +26,8 @@ const (
EnvDynamoServicePort = "PORT" EnvDynamoServicePort = "PORT"
EnvDockerRegistryServer = "DOCKER_REGISTRY_SERVER" EnvDockerRegistryServer = "DOCKER_REGISTRY_SERVER"
EnvDockerRegistryInClusterServer = "DOCKER_REGISTRY_IN_CLUSTER_SERVER" EnvDockerRegistrySecret = "DOCKER_REGISTRY_SECRET_NAME"
EnvDockerRegistryUsername = "DOCKER_REGISTRY_USERNAME"
// nolint:gosec
EnvDockerRegistryPassword = "DOCKER_REGISTRY_PASSWORD"
EnvDockerRegistrySecure = "DOCKER_REGISTRY_SECURE" EnvDockerRegistrySecure = "DOCKER_REGISTRY_SECURE"
EnvDockerRegistryDynamoComponentsRepositoryName = "DOCKER_REGISTRY_DYNAMO_COMPONENTS_REPOSITORY_NAME" EnvDockerRegistryDynamoComponentsRepositoryName = "DOCKER_REGISTRY_DYNAMO_COMPONENTS_REPOSITORY_NAME"
...@@ -49,8 +46,7 @@ const ( ...@@ -49,8 +46,7 @@ const (
KubeLabelDynamoComponentType = "nvidia.com/dynamo-component-type" KubeLabelDynamoComponentType = "nvidia.com/dynamo-component-type"
KubeLabelIsDynamoImageBuilder = "nvidia.com/is-dynamo-image-builder" KubeLabelIsDynamoImageBuilder = "nvidia.com/is-dynamo-image-builder"
KubeLabelDynamoComponentRequest = "nvidia.com/dynamo-component-request"
KubeLabelValueFalse = "false" KubeLabelValueFalse = "false"
KubeLabelValueTrue = "true" KubeLabelValueTrue = "true"
...@@ -64,10 +60,7 @@ const ( ...@@ -64,10 +60,7 @@ const (
KubeResourceGPUNvidia = "nvidia.com/gpu" KubeResourceGPUNvidia = "nvidia.com/gpu"
// nolint: gosec KubeAnnotationDynamoComponentHash = "nvidia.com/dynamo-request-hash"
KubeSecretNameRegcred = "dynamo-regcred" KubeAnnotationDynamoComponentImageBuiderHash = "nvidia.com/dynamo-request-image-builder-hash"
KubeAnnotationDynamoComponentStorageNS = "nvidia.com/dynamo-storage-namespace"
KubeAnnotationDynamoComponentRequestHash = "nvidia.com/dynamo-request-hash"
KubeAnnotationDynamoComponentRequestImageBuiderHash = "nvidia.com/dynamo-request-image-builder-hash"
KubeAnnotationDynamoComponentStorageNS = "nvidia.com/dynamo-storage-namespace"
) )
...@@ -26,34 +26,6 @@ import ( ...@@ -26,34 +26,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
const (
EntityHandlerTypeJob = "job"
// EntityHandlerCreated indicates that the EntityHandler is created.
EntityHandlerCreated = "ENTITY_HANDLER_CREATED"
// EntityHandlerCompleted indicates that the EntityHandler has completed.
EntityHandlerCompleted = "ENTITY_HANDLER_COMPLETED"
// EntityHandlerPending indicates that the EntityHandler is in pending state.
EntityHandlerPending = "ENTITY_HANDLER_PENDING"
EntityHandlerCreatedState = "EntityHandlerCreated"
EntityHandlerCompletedState = "EntityHandlerCompleted"
EntityHandlerFailedState = "EntityHandlerFailed"
EntityHandlerPendingState = "EntityHandlerPending"
EntityHandlerRunningState = "EntityHandlerRunning"
PVCCreatedState = "PVCCreated"
CrdRunning = "running"
CrdFailed = "failed"
CrdSuccessful = "successful"
PVCMountPath = "/pvc"
// TrainingJobPVCCreated indicates that the caching pvc is created.
PVCCreated = "PVC_CREATED"
)
func constructPVC(crd metav1.Object, pvcConfig v1alpha1.PVC) *corev1.PersistentVolumeClaim { func constructPVC(crd metav1.Object, pvcConfig v1alpha1.PVC) *corev1.PersistentVolumeClaim {
storageClassName := pvcConfig.StorageClass storageClassName := pvcConfig.StorageClass
return &corev1.PersistentVolumeClaim{ return &corev1.PersistentVolumeClaim{
......
...@@ -29,7 +29,6 @@ import ( ...@@ -29,7 +29,6 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
...@@ -70,17 +69,21 @@ import ( ...@@ -70,17 +69,21 @@ import (
nvidiacomv1alpha1 "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/v1alpha1" nvidiacomv1alpha1 "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/v1alpha1"
) )
// DynamoComponentRequestReconciler reconciles a DynamoComponentRequest object const (
type DynamoComponentRequestReconciler struct { dockerConfigSecretKey = ".dockerconfigjson"
)
// DynamoComponentReconciler reconciles a DynamoComponent object
type DynamoComponentReconciler struct {
client.Client client.Client
Scheme *runtime.Scheme Scheme *runtime.Scheme
Recorder record.EventRecorder Recorder record.EventRecorder
Config controller_common.Config Config controller_common.Config
} }
// +kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponentrequests,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponents,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponentrequests/status,verbs=get;update;patch // +kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponents/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponentrequests/finalizers,verbs=update // +kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponents/finalizers,verbs=update
//+kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponents,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponents,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponents/status,verbs=get;update;patch //+kubebuilder:rbac:groups=nvidia.com,resources=dynamocomponents/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=get;list;watch;create;update;patch;delete
...@@ -94,7 +97,7 @@ type DynamoComponentRequestReconciler struct { ...@@ -94,7 +97,7 @@ type DynamoComponentRequestReconciler struct {
// Reconcile is part of the main kubernetes reconciliation loop which aims to // Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state. // move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by // TODO(user): Modify the Reconcile function to compare the state specified by
// the DynamoComponentRequest object against the actual cluster state, and then // the DynamoComponent object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by // perform operations to make the cluster state reflect the state specified by
// the user. // the user.
// //
...@@ -102,52 +105,50 @@ type DynamoComponentRequestReconciler struct { ...@@ -102,52 +105,50 @@ type DynamoComponentRequestReconciler struct {
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.18.2/pkg/reconcile // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.18.2/pkg/reconcile
// //
//nolint:gocyclo,nakedret //nolint:gocyclo,nakedret
func (r *DynamoComponentRequestReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { func (r *DynamoComponentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) {
logs := log.FromContext(ctx) logs := log.FromContext(ctx)
dynamoComponentRequest := &nvidiacomv1alpha1.DynamoComponentRequest{} DynamoComponent := &nvidiacomv1alpha1.DynamoComponent{}
err = r.Get(ctx, req.NamespacedName, dynamoComponentRequest) err = r.Get(ctx, req.NamespacedName, DynamoComponent)
if err != nil { if err != nil {
if k8serrors.IsNotFound(err) { if k8serrors.IsNotFound(err) {
// Object not found, return. Created objects are automatically garbage collected. // Object not found, return. Created objects are automatically garbage collected.
// For additional cleanup logic use finalizers. // For additional cleanup logic use finalizers.
logs.Info("dynamoComponentRequest resource not found. Ignoring since object must be deleted") logs.Info("DynamoComponent resource not found. Ignoring since object must be deleted")
err = nil err = nil
return return
} }
// Error reading the object - requeue the request. // Error reading the object - requeue the request.
logs.Error(err, "Failed to get dynamoComponentRequest") logs.Error(err, "Failed to get DynamoComponent")
return return
} }
for _, condition := range dynamoComponentRequest.Status.Conditions { if DynamoComponent.IsReady() {
if condition.Type == nvidiacomv1alpha1.DynamoGraphDeploymentConditionTypeAvailable && condition.Status == metav1.ConditionTrue { logs.Info("Skip available DynamoComponent")
logs.Info("Skip available dynamoComponentRequest") return
return
}
} }
if len(dynamoComponentRequest.Status.Conditions) == 0 { if len(DynamoComponent.Status.Conditions) == 0 {
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, DynamoComponent, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeModelsSeeding, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageBuilding,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: "Starting to reconcile dynamoComponentRequest", Message: "Starting to reconcile DynamoComponent",
}, },
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageBuilding, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageExists,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: "Starting to reconcile dynamoComponentRequest", Message: "Starting to reconcile DynamoComponent",
}, },
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExists, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeDynamoComponentAvailable,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: "Starting to reconcile dynamoComponentRequest", Message: "Reconciling",
}, },
) )
if err != nil { if err != nil {
...@@ -155,47 +156,32 @@ func (r *DynamoComponentRequestReconciler) Reconcile(ctx context.Context, req ct ...@@ -155,47 +156,32 @@ func (r *DynamoComponentRequestReconciler) Reconcile(ctx context.Context, req ct
} }
} }
logs = logs.WithValues("dynamoComponentRequest", dynamoComponentRequest.Name, "dynamoComponentRequestNamespace", dynamoComponentRequest.Namespace) logs = logs.WithValues("DynamoComponent", DynamoComponent.Name, "DynamoComponentNamespace", DynamoComponent.Namespace)
defer func() { defer func() {
if err == nil { if err == nil {
logs.Info("Reconcile success") logs.Info("Reconcile success")
return return
} }
logs.Error(err, "Failed to reconcile dynamoComponentRequest.") logs.Error(err, "Failed to reconcile DynamoComponent.")
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeWarning, "ReconcileError", "Failed to reconcile dynamoComponentRequest: %v", err) r.Recorder.Eventf(DynamoComponent, corev1.EventTypeWarning, "ReconcileError", "Failed to reconcile DynamoComponent: %v", err)
_, err_ := r.setStatusConditions(ctx, req, _, err_ := r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeDynamoComponentAvailable, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeDynamoComponentAvailable,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: err.Error(), Message: err.Error(),
}, },
) )
if err_ != nil { if err_ != nil {
logs.Error(err_, "Failed to update dynamoComponentRequest status") logs.Error(err_, "Failed to update DynamoComponent status")
return return
} }
}() }()
dynamoComponentAvailableCondition := meta.FindStatusCondition(dynamoComponentRequest.Status.Conditions, nvidiacomv1alpha1.DynamoComponentRequestConditionTypeDynamoComponentAvailable) DynamoComponent, _, imageExists, imageExistsResult, err := r.ensureImageExists(ctx, ensureImageExistsOption{
if dynamoComponentAvailableCondition == nil || dynamoComponentAvailableCondition.Status != metav1.ConditionUnknown { DynamoComponent: DynamoComponent,
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, req: req,
metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeDynamoComponentAvailable,
Status: metav1.ConditionUnknown,
Reason: "Reconciling",
Message: "Reconciling",
},
)
if err != nil {
return
}
}
dynamoComponentRequest, imageInfo, imageExists, imageExistsResult, err := r.ensureImageExists(ctx, ensureImageExistsOption{
dynamoComponentRequest: dynamoComponentRequest,
req: req,
}) })
if err != nil { if err != nil {
...@@ -205,9 +191,9 @@ func (r *DynamoComponentRequestReconciler) Reconcile(ctx context.Context, req ct ...@@ -205,9 +191,9 @@ func (r *DynamoComponentRequestReconciler) Reconcile(ctx context.Context, req ct
if !imageExists { if !imageExists {
result = imageExistsResult result = imageExistsResult
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, DynamoComponent, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeDynamoComponentAvailable, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeDynamoComponentAvailable,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: "DynamoComponent image is building", Message: "DynamoComponent image is building",
...@@ -219,64 +205,12 @@ func (r *DynamoComponentRequestReconciler) Reconcile(ctx context.Context, req ct ...@@ -219,64 +205,12 @@ func (r *DynamoComponentRequestReconciler) Reconcile(ctx context.Context, req ct
return return
} }
dynamoComponentCR := &nvidiacomv1alpha1.DynamoComponent{ DynamoComponent, err = r.setStatusConditions(ctx, req,
ObjectMeta: metav1.ObjectMeta{
Name: dynamoComponentRequest.Name,
Namespace: dynamoComponentRequest.Namespace,
},
Spec: nvidiacomv1alpha1.DynamoComponentSpec{
DynamoComponent: dynamoComponentRequest.Spec.DynamoComponent,
Image: imageInfo.ImageName,
ServiceName: dynamoComponentRequest.Spec.ServiceName,
},
}
err = ctrl.SetControllerReference(dynamoComponentRequest, dynamoComponentCR, r.Scheme)
if err != nil {
err = errors.Wrap(err, "set controller reference")
return
}
if imageInfo.DockerConfigJSONSecretName != "" {
dynamoComponentCR.Spec.ImagePullSecrets = []corev1.LocalObjectReference{
{
Name: imageInfo.DockerConfigJSONSecretName,
},
}
}
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "DynamoComponentImageBuilder", "Creating DynamoComponent CR %s in namespace %s", dynamoComponentCR.Name, dynamoComponentCR.Namespace)
err = r.Create(ctx, dynamoComponentCR)
isAlreadyExists := k8serrors.IsAlreadyExists(err)
if err != nil && !isAlreadyExists {
err = errors.Wrap(err, "create DynamoComponent resource")
return
}
if isAlreadyExists {
oldDynamoComponentCR := &nvidiacomv1alpha1.DynamoComponent{}
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "DynamoComponentImageBuilder", "Updating DynamoComponent CR %s in namespace %s", dynamoComponentCR.Name, dynamoComponentCR.Namespace)
err = r.Get(ctx, types.NamespacedName{Name: dynamoComponentCR.Name, Namespace: dynamoComponentCR.Namespace}, oldDynamoComponentCR)
if err != nil {
err = errors.Wrap(err, "get DynamoComponent resource")
return
}
if !reflect.DeepEqual(oldDynamoComponentCR.Spec, dynamoComponentCR.Spec) {
oldDynamoComponentCR.OwnerReferences = dynamoComponentCR.OwnerReferences
oldDynamoComponentCR.Spec = dynamoComponentCR.Spec
err = r.Update(ctx, oldDynamoComponentCR)
if err != nil {
err = errors.Wrap(err, "update DynamoComponent resource")
return
}
}
}
dynamoComponentRequest, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeDynamoComponentAvailable, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeDynamoComponentAvailable,
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
Reason: "Reconciling", Reason: "Reconciling",
Message: "DynamoComponent is generated", Message: "DynamoComponent image is generated",
}, },
) )
if err != nil { if err != nil {
...@@ -291,100 +225,100 @@ func isEstargzEnabled() bool { ...@@ -291,100 +225,100 @@ func isEstargzEnabled() bool {
} }
type ensureImageExistsOption struct { type ensureImageExistsOption struct {
dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest DynamoComponent *nvidiacomv1alpha1.DynamoComponent
req ctrl.Request req ctrl.Request
} }
//nolint:gocyclo,nakedret //nolint:gocyclo,nakedret
func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context, opt ensureImageExistsOption) (dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest, imageInfo ImageInfo, imageExists bool, result ctrl.Result, err error) { // nolint: unparam func (r *DynamoComponentReconciler) ensureImageExists(ctx context.Context, opt ensureImageExistsOption) (DynamoComponent *nvidiacomv1alpha1.DynamoComponent, imageInfo ImageInfo, imageExists bool, result ctrl.Result, err error) { // nolint: unparam
logs := log.FromContext(ctx) logs := log.FromContext(ctx)
dynamoComponentRequest = opt.dynamoComponentRequest DynamoComponent = opt.DynamoComponent
req := opt.req req := opt.req
imageInfo, err = r.getImageInfo(ctx, GetImageInfoOption{ imageInfo, err = r.getImageInfo(ctx, GetImageInfoOption{
DynamoComponentRequest: dynamoComponentRequest, DynamoComponent: DynamoComponent,
}) })
if err != nil { if err != nil {
err = errors.Wrap(err, "get image info") err = errors.Wrap(err, "get image info")
return return
} }
imageExistsCheckedCondition := meta.FindStatusCondition(dynamoComponentRequest.Status.Conditions, nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExistsChecked) imageExistsCheckedCondition := meta.FindStatusCondition(DynamoComponent.Status.Conditions, nvidiacomv1alpha1.DynamoComponentConditionTypeImageExistsChecked)
imageExistsCondition := meta.FindStatusCondition(dynamoComponentRequest.Status.Conditions, nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExists) imageExistsCondition := meta.FindStatusCondition(DynamoComponent.Status.Conditions, nvidiacomv1alpha1.DynamoComponentConditionTypeImageExists)
if imageExistsCheckedCondition == nil || imageExistsCheckedCondition.Status != metav1.ConditionTrue || imageExistsCheckedCondition.Message != imageInfo.ImageName { if imageExistsCheckedCondition == nil || imageExistsCheckedCondition.Status != metav1.ConditionTrue || imageExistsCheckedCondition.Message != imageInfo.ImageName {
imageExistsCheckedCondition = &metav1.Condition{ imageExistsCheckedCondition = &metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExistsChecked, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageExistsChecked,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: imageInfo.ImageName, Message: imageInfo.ImageName,
} }
dynamoComponentAvailableCondition := &metav1.Condition{ dynamoComponentAvailableCondition := &metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeDynamoComponentAvailable, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeDynamoComponentAvailable,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: "Checking image exists", Message: "Checking image exists",
} }
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, *imageExistsCheckedCondition, *dynamoComponentAvailableCondition) DynamoComponent, err = r.setStatusConditions(ctx, req, *imageExistsCheckedCondition, *dynamoComponentAvailableCondition)
if err != nil { if err != nil {
return return
} }
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "CheckingImage", "Checking image exists: %s", imageInfo.ImageName) r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "CheckingImage", "Checking image exists: %s", imageInfo.ImageName)
imageExists, err = checkImageExists(dynamoComponentRequest, imageInfo.DockerRegistry, imageInfo.InClusterImageName) imageExists, err = checkImageExists(DynamoComponent, imageInfo.DockerRegistry, imageInfo.ImageName)
if err != nil { if err != nil {
err = errors.Wrapf(err, "check image %s exists", imageInfo.ImageName) err = errors.Wrapf(err, "check image %s exists", imageInfo.ImageName)
return return
} }
err = r.Get(ctx, req.NamespacedName, dynamoComponentRequest) err = r.Get(ctx, req.NamespacedName, DynamoComponent)
if err != nil { if err != nil {
logs.Error(err, "Failed to re-fetch dynamoComponentRequest") logs.Error(err, "Failed to re-fetch DynamoComponent")
return return
} }
if imageExists { if imageExists {
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "CheckingImage", "Image exists: %s", imageInfo.ImageName) r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "CheckingImage", "Image exists: %s", imageInfo.ImageName)
imageExistsCheckedCondition = &metav1.Condition{ imageExistsCheckedCondition = &metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExistsChecked, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageExistsChecked,
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
Reason: "Reconciling", Reason: "Reconciling",
Message: imageInfo.ImageName, Message: imageInfo.ImageName,
} }
imageExistsCondition = &metav1.Condition{ imageExistsCondition = &metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExists, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageExists,
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
Reason: "Reconciling", Reason: "Reconciling",
Message: imageInfo.ImageName, Message: imageInfo.ImageName,
} }
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, *imageExistsCondition, *imageExistsCheckedCondition) DynamoComponent, err = r.setStatusConditions(ctx, req, *imageExistsCondition, *imageExistsCheckedCondition)
if err != nil { if err != nil {
return return
} }
} else { } else {
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "CheckingImage", "Image not exists: %s", imageInfo.ImageName) r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "CheckingImage", "Image not exists: %s", imageInfo.ImageName)
imageExistsCheckedCondition = &metav1.Condition{ imageExistsCheckedCondition = &metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExistsChecked, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageExistsChecked,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: fmt.Sprintf("Image not exists: %s", imageInfo.ImageName), Message: fmt.Sprintf("Image not exists: %s", imageInfo.ImageName),
} }
imageExistsCondition = &metav1.Condition{ imageExistsCondition = &metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExists, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageExists,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: fmt.Sprintf("Image %s is not exists", imageInfo.ImageName), Message: fmt.Sprintf("Image %s is not exists", imageInfo.ImageName),
} }
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, *imageExistsCondition, *imageExistsCheckedCondition) DynamoComponent, err = r.setStatusConditions(ctx, req, *imageExistsCondition, *imageExistsCheckedCondition)
if err != nil { if err != nil {
return return
} }
} }
} }
var dynamoComponentRequestHashStr string var DynamoComponentHashStr string
dynamoComponentRequestHashStr, err = r.getHashStr(dynamoComponentRequest) DynamoComponentHashStr, err = r.getHashStr(DynamoComponent)
if err != nil { if err != nil {
err = errors.Wrapf(err, "get dynamoComponentRequest %s/%s hash string", dynamoComponentRequest.Namespace, dynamoComponentRequest.Name) err = errors.Wrapf(err, "get DynamoComponent %s/%s hash string", DynamoComponent.Namespace, DynamoComponent.Name)
return return
} }
...@@ -394,8 +328,8 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context ...@@ -394,8 +328,8 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context
} }
jobLabels := map[string]string{ jobLabels := map[string]string{
commonconsts.KubeLabelDynamoComponentRequest: dynamoComponentRequest.Name, commonconsts.KubeLabelDynamoComponent: DynamoComponent.Name,
commonconsts.KubeLabelIsDynamoImageBuilder: commonconsts.KubeLabelValueTrue, commonconsts.KubeLabelIsDynamoImageBuilder: commonconsts.KubeLabelValueTrue,
} }
jobs := &batchv1.JobList{} jobs := &batchv1.JobList{}
...@@ -409,9 +343,9 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context ...@@ -409,9 +343,9 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context
for _, job_ := range jobs.Items { for _, job_ := range jobs.Items {
job_ := job_ job_ := job_
oldHash := job_.Annotations[consts.KubeAnnotationDynamoComponentRequestHash] oldHash := job_.Annotations[consts.KubeAnnotationDynamoComponentHash]
if oldHash != dynamoComponentRequestHashStr { if oldHash != DynamoComponentHashStr {
logs.Info("Because hash changed, delete old job", "job", job_.Name, "oldHash", oldHash, "newHash", dynamoComponentRequestHashStr) logs.Info("Because hash changed, delete old job", "job", job_.Name, "oldHash", oldHash, "newHash", DynamoComponentHashStr)
// --cascade=foreground // --cascade=foreground
err = r.Delete(ctx, &job_, &client.DeleteOptions{ err = r.Delete(ctx, &job_, &client.DeleteOptions{
PropagationPolicy: &[]metav1.DeletionPropagation{metav1.DeletePropagationForeground}[0], PropagationPolicy: &[]metav1.DeletionPropagation{metav1.DeletePropagationForeground}[0],
...@@ -447,31 +381,31 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context ...@@ -447,31 +381,31 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context
if job == nil { if job == nil {
job, err = r.generateImageBuilderJob(ctx, GenerateImageBuilderJobOption{ job, err = r.generateImageBuilderJob(ctx, GenerateImageBuilderJobOption{
ImageInfo: imageInfo, ImageInfo: imageInfo,
DynamoComponentRequest: dynamoComponentRequest, DynamoComponent: DynamoComponent,
}) })
if err != nil { if err != nil {
err = errors.Wrap(err, "generate image builder job") err = errors.Wrap(err, "generate image builder job")
return return
} }
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderJob", "Creating image builder job: %s", job.Name) r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderJob", "Creating image builder job: %s", job.Name)
err = r.Create(ctx, job) err = r.Create(ctx, job)
if err != nil { if err != nil {
err = errors.Wrapf(err, "create image builder job %s", job.Name) err = errors.Wrapf(err, "create image builder job %s", job.Name)
return return
} }
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderJob", "Created image builder job: %s", job.Name) r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderJob", "Created image builder job: %s", job.Name)
return return
} }
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "CheckingImageBuilderJob", "Found image builder job: %s", job.Name) r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "CheckingImageBuilderJob", "Found image builder job: %s", job.Name)
err = r.Get(ctx, req.NamespacedName, dynamoComponentRequest) err = r.Get(ctx, req.NamespacedName, DynamoComponent)
if err != nil { if err != nil {
logs.Error(err, "Failed to re-fetch dynamoComponentRequest") logs.Error(err, "Failed to re-fetch DynamoComponent")
return return
} }
imageBuildingCondition := meta.FindStatusCondition(dynamoComponentRequest.Status.Conditions, nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageBuilding) imageBuildingCondition := meta.FindStatusCondition(DynamoComponent.Status.Conditions, nvidiacomv1alpha1.DynamoComponentConditionTypeImageBuilding)
isJobFailed := false isJobFailed := false
isJobRunning := true isJobRunning := true
...@@ -496,23 +430,23 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context ...@@ -496,23 +430,23 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context
conditions := make([]metav1.Condition, 0) conditions := make([]metav1.Condition, 0)
if job.Status.Active > 0 { if job.Status.Active > 0 {
conditions = append(conditions, metav1.Condition{ conditions = append(conditions, metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageBuilding, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageBuilding,
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
Reason: "Reconciling", Reason: "Reconciling",
Message: fmt.Sprintf("Image building job %s is running", job.Name), Message: fmt.Sprintf("Image building job %s is running", job.Name),
}) })
} else { } else {
conditions = append(conditions, metav1.Condition{ conditions = append(conditions, metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageBuilding, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageBuilding,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: fmt.Sprintf("Image building job %s is waiting", job.Name), Message: fmt.Sprintf("Image building job %s is waiting", job.Name),
}) })
} }
if dynamoComponentRequest.Spec.ImageBuildTimeout != nil { if DynamoComponent.Spec.ImageBuildTimeout != nil {
if imageBuildingCondition != nil && imageBuildingCondition.LastTransitionTime.Add(time.Duration(*dynamoComponentRequest.Spec.ImageBuildTimeout)).Before(time.Now()) { if imageBuildingCondition != nil && imageBuildingCondition.LastTransitionTime.Add(time.Duration(*DynamoComponent.Spec.ImageBuildTimeout)).Before(time.Now()) {
conditions = append(conditions, metav1.Condition{ conditions = append(conditions, metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageBuilding, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageBuilding,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: "Timeout", Reason: "Timeout",
Message: fmt.Sprintf("Image building job %s is timeout", job.Name), Message: fmt.Sprintf("Image building job %s is timeout", job.Name),
...@@ -525,27 +459,27 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context ...@@ -525,27 +459,27 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context
} }
} }
if dynamoComponentRequest, err = r.setStatusConditions(ctx, req, conditions...); err != nil { if DynamoComponent, err = r.setStatusConditions(ctx, req, conditions...); err != nil {
return return
} }
if imageBuildingCondition != nil && imageBuildingCondition.Status != metav1.ConditionTrue && isJobRunning { if imageBuildingCondition != nil && imageBuildingCondition.Status != metav1.ConditionTrue && isJobRunning {
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "DynamoComponentImageBuilder", "Image is building now") r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "DynamoComponentImageBuilder", "Image is building now")
} }
return return
} }
if isJobFailed { if isJobFailed {
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, DynamoComponent, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageBuilding, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageBuilding,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: fmt.Sprintf("Image building job %s is failed.", job.Name), Message: fmt.Sprintf("Image building job %s is failed.", job.Name),
}, },
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeDynamoComponentAvailable, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeDynamoComponentAvailable,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: fmt.Sprintf("Image building job %s is failed.", job.Name), Message: fmt.Sprintf("Image building job %s is failed.", job.Name),
...@@ -557,15 +491,15 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context ...@@ -557,15 +491,15 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context
return return
} }
dynamoComponentRequest, err = r.setStatusConditions(ctx, req, DynamoComponent, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageBuilding, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageBuilding,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: fmt.Sprintf("Image building job %s is succeeded.", job.Name), Message: fmt.Sprintf("Image building job %s is succeeded.", job.Name),
}, },
metav1.Condition{ metav1.Condition{
Type: nvidiacomv1alpha1.DynamoComponentRequestConditionTypeImageExists, Type: nvidiacomv1alpha1.DynamoComponentConditionTypeImageExists,
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
Reason: "Reconciling", Reason: "Reconciling",
Message: imageInfo.ImageName, Message: imageInfo.ImageName,
...@@ -575,40 +509,40 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context ...@@ -575,40 +509,40 @@ func (r *DynamoComponentRequestReconciler) ensureImageExists(ctx context.Context
return return
} }
r.Recorder.Eventf(dynamoComponentRequest, corev1.EventTypeNormal, "DynamoComponentImageBuilder", "Image has been built successfully") r.Recorder.Eventf(DynamoComponent, corev1.EventTypeNormal, "DynamoComponentImageBuilder", "Image has been built successfully")
imageExists = true imageExists = true
return return
} }
func (r *DynamoComponentRequestReconciler) setStatusConditions(ctx context.Context, req ctrl.Request, conditions ...metav1.Condition) (dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest, err error) { func (r *DynamoComponentReconciler) setStatusConditions(ctx context.Context, req ctrl.Request, conditions ...metav1.Condition) (DynamoComponent *nvidiacomv1alpha1.DynamoComponent, err error) {
dynamoComponentRequest = &nvidiacomv1alpha1.DynamoComponentRequest{} DynamoComponent = &nvidiacomv1alpha1.DynamoComponent{}
/* /*
Please don't blame me when you see this kind of code, Please don't blame me when you see this kind of code,
this is to avoid "the object has been modified; please apply your changes to the latest version and try again" when updating CR status, this is to avoid "the object has been modified; please apply your changes to the latest version and try again" when updating CR status,
don't doubt that almost all CRD operators (e.g. cert-manager) can't avoid this stupid error and can only try to avoid this by this stupid way. don't doubt that almost all CRD operators (e.g. cert-manager) can't avoid this stupid error and can only try to avoid this by this stupid way.
*/ */
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
if err = r.Get(ctx, req.NamespacedName, dynamoComponentRequest); err != nil { if err = r.Get(ctx, req.NamespacedName, DynamoComponent); err != nil {
err = errors.Wrap(err, "Failed to re-fetch dynamoComponentRequest") err = errors.Wrap(err, "Failed to re-fetch DynamoComponent")
return return
} }
for _, condition := range conditions { for _, condition := range conditions {
meta.SetStatusCondition(&dynamoComponentRequest.Status.Conditions, condition) meta.SetStatusCondition(&DynamoComponent.Status.Conditions, condition)
} }
if err = r.Status().Update(ctx, dynamoComponentRequest); err != nil { if err = r.Status().Update(ctx, DynamoComponent); err != nil {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
} else { } else {
break break
} }
} }
if err != nil { if err != nil {
err = errors.Wrap(err, "Failed to update dynamoComponentRequest status") err = errors.Wrap(err, "Failed to update DynamoComponent status")
return return
} }
if err = r.Get(ctx, req.NamespacedName, dynamoComponentRequest); err != nil { if err = r.Get(ctx, req.NamespacedName, DynamoComponent); err != nil {
err = errors.Wrap(err, "Failed to re-fetch dynamoComponentRequest") err = errors.Wrap(err, "Failed to re-fetch DynamoComponent")
return return
} }
return return
...@@ -635,85 +569,7 @@ func getDynamoComponentImageBuildEngine() DynamoComponentImageBuildEngine { ...@@ -635,85 +569,7 @@ func getDynamoComponentImageBuildEngine() DynamoComponentImageBuildEngine {
} }
//nolint:nakedret //nolint:nakedret
func (r *DynamoComponentRequestReconciler) makeSureDockerConfigJSONSecret(ctx context.Context, namespace string, dockerRegistryConf *commonconfig.DockerRegistryConfig) (dockerConfigJSONSecret *corev1.Secret, err error) { func (r *DynamoComponentReconciler) getApiStoreClient(ctx context.Context) (*apiStoreClient.ApiStoreClient, *commonconfig.ApiStoreConfig, error) {
if dockerRegistryConf.Username == "" {
return
}
// nolint: gosec
dockerConfigSecretName := commonconsts.KubeSecretNameRegcred
dockerConfigObj := struct {
Auths map[string]struct {
Auth string `json:"auth"`
} `json:"auths"`
}{
Auths: map[string]struct {
Auth string `json:"auth"`
}{
dockerRegistryConf.Server: {
Auth: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", dockerRegistryConf.Username, dockerRegistryConf.Password))),
},
},
}
dockerConfigContent, err := json.Marshal(dockerConfigObj)
if err != nil {
err = errors.Wrap(err, "marshal docker config")
return nil, err
}
dockerConfigJSONSecret = &corev1.Secret{}
err = r.Get(ctx, types.NamespacedName{Namespace: namespace, Name: dockerConfigSecretName}, dockerConfigJSONSecret)
dockerConfigIsNotFound := k8serrors.IsNotFound(err)
// nolint: gocritic
if err != nil && !dockerConfigIsNotFound {
err = errors.Wrap(err, "get docker config secret")
return nil, err
}
err = nil
if dockerConfigIsNotFound {
dockerConfigJSONSecret = &corev1.Secret{
Type: corev1.SecretTypeDockerConfigJson,
ObjectMeta: metav1.ObjectMeta{
Name: dockerConfigSecretName,
Namespace: namespace,
},
Data: map[string][]byte{
".dockerconfigjson": dockerConfigContent,
},
}
err_ := r.Create(ctx, dockerConfigJSONSecret)
if err_ != nil {
dockerConfigJSONSecret = &corev1.Secret{}
err = r.Get(ctx, types.NamespacedName{Namespace: namespace, Name: dockerConfigSecretName}, dockerConfigJSONSecret)
dockerConfigIsNotFound = k8serrors.IsNotFound(err)
if err != nil && !dockerConfigIsNotFound {
err = errors.Wrap(err, "get docker config secret")
return nil, err
}
if dockerConfigIsNotFound {
err_ = errors.Wrap(err_, "create docker config secret")
return nil, err_
}
if err != nil {
err = nil
}
}
} else {
dockerConfigJSONSecret.Data[".dockerconfigjson"] = dockerConfigContent
err = r.Update(ctx, dockerConfigJSONSecret)
if err != nil {
err = errors.Wrap(err, "update docker config secret")
return nil, err
}
}
return
}
//nolint:nakedret
func (r *DynamoComponentRequestReconciler) getApiStoreClient(ctx context.Context) (*apiStoreClient.ApiStoreClient, *commonconfig.ApiStoreConfig, error) {
apiStoreConf, err := commonconfig.GetApiStoreConfig(ctx) apiStoreConf, err := commonconfig.GetApiStoreConfig(ctx)
isNotFound := k8serrors.IsNotFound(err) isNotFound := k8serrors.IsNotFound(err)
if err != nil && !isNotFound { if err != nil && !isNotFound {
...@@ -738,84 +594,69 @@ func (r *DynamoComponentRequestReconciler) getApiStoreClient(ctx context.Context ...@@ -738,84 +594,69 @@ func (r *DynamoComponentRequestReconciler) getApiStoreClient(ctx context.Context
return apiStoreClient, apiStoreConf, nil return apiStoreClient, apiStoreConf, nil
} }
//nolint:nakedret func (r *DynamoComponentReconciler) RetrieveDockerRegistrySecret(ctx context.Context, secretName string, namespace string, dockerRegistry *schemas.DockerRegistrySchema) error {
func (r *DynamoComponentRequestReconciler) getDockerRegistry(ctx context.Context, dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest) (dockerRegistry schemas.DockerRegistrySchema, err error) { secret := &corev1.Secret{}
if dynamoComponentRequest != nil && dynamoComponentRequest.Spec.DockerConfigJSONSecretName != "" { err := r.Get(ctx, types.NamespacedName{
secret := &corev1.Secret{} Namespace: namespace,
err = r.Get(ctx, types.NamespacedName{ Name: secretName,
Namespace: dynamoComponentRequest.Namespace, }, secret)
Name: dynamoComponentRequest.Spec.DockerConfigJSONSecretName, if err != nil {
}, secret) err = errors.Wrapf(err, "get docker config json secret %s", secretName)
if err != nil { return err
err = errors.Wrapf(err, "get docker config json secret %s", dynamoComponentRequest.Spec.DockerConfigJSONSecretName) }
return configJSON, ok := secret.Data[dockerConfigSecretKey]
} if !ok {
configJSON, ok := secret.Data[".dockerconfigjson"] err = errors.Errorf("docker config json secret %s does not have %s key", secretName, dockerConfigSecretKey)
if !ok { return err
err = errors.Errorf("docker config json secret %s does not have .dockerconfigjson key", dynamoComponentRequest.Spec.DockerConfigJSONSecretName) }
return var configObj struct {
} Auths map[string]struct {
var configObj struct { Auth string `json:"auth"`
Auths map[string]struct { } `json:"auths"`
Auth string `json:"auth"` }
} `json:"auths"` err = json.Unmarshal(configJSON, &configObj)
} if err != nil {
err = json.Unmarshal(configJSON, &configObj) err = errors.Wrapf(err, "unmarshal docker config json secret %s", secretName)
if err != nil { return err
err = errors.Wrapf(err, "unmarshal docker config json secret %s", dynamoComponentRequest.Spec.DockerConfigJSONSecretName) }
return var server string
var auth string
if dockerRegistry.Server != "" {
for k, v := range configObj.Auths {
if k == dockerRegistry.Server {
server = k
auth = v.Auth
break
}
} }
imageRegistryURI, _, _ := xstrings.Partition(dynamoComponentRequest.Spec.Image, "/") if server == "" {
var server string
var auth string
if imageRegistryURI != "" {
for k, v := range configObj.Auths { for k, v := range configObj.Auths {
if k == imageRegistryURI { if strings.Contains(k, dockerRegistry.Server) {
server = k server = k
auth = v.Auth auth = v.Auth
break break
} }
} }
if server == "" {
for k, v := range configObj.Auths {
if strings.Contains(k, imageRegistryURI) {
server = k
auth = v.Auth
break
}
}
}
}
if server == "" {
for k, v := range configObj.Auths {
server = k
auth = v.Auth
break
}
} }
if server == "" {
err = errors.Errorf("no auth in docker config json secret %s", dynamoComponentRequest.Spec.DockerConfigJSONSecretName)
return
}
dockerRegistry.Server = server
var credentials []byte
credentials, err = base64.StdEncoding.DecodeString(auth)
if err != nil {
err = errors.Wrapf(err, "cannot base64 decode auth in docker config json secret %s", dynamoComponentRequest.Spec.DockerConfigJSONSecretName)
return
}
dockerRegistry.Username, _, dockerRegistry.Password = xstrings.Partition(string(credentials), ":")
if dynamoComponentRequest.Spec.OCIRegistryInsecure != nil {
dockerRegistry.Secure = !*dynamoComponentRequest.Spec.OCIRegistryInsecure
}
return
} }
if server == "" {
dockerRegistryConfig, err := commonconfig.GetDockerRegistryConfig() err = errors.Errorf("no auth in docker config json secret %s for server %s", secretName, dockerRegistry.Server)
return err
}
var credentials []byte
credentials, err = base64.StdEncoding.DecodeString(auth)
if err != nil { if err != nil {
err = errors.Wrap(err, "get docker registry") err = errors.Wrapf(err, "cannot base64 decode auth in docker config json secret %s", secretName)
return return err
} }
dockerRegistry.Username, _, dockerRegistry.Password = xstrings.Partition(string(credentials), ":")
return nil
}
//nolint:nakedret
func (r *DynamoComponentReconciler) getDockerRegistry(ctx context.Context, DynamoComponent *nvidiacomv1alpha1.DynamoComponent) (dockerRegistry *schemas.DockerRegistrySchema, err error) {
dockerRegistryConfig := commonconfig.GetDockerRegistryConfig()
dynamoRepositoryName := "dynamo-components" dynamoRepositoryName := "dynamo-components"
if dockerRegistryConfig.DynamoComponentsRepositoryName != "" { if dockerRegistryConfig.DynamoComponentsRepositoryName != "" {
...@@ -825,20 +666,22 @@ func (r *DynamoComponentRequestReconciler) getDockerRegistry(ctx context.Context ...@@ -825,20 +666,22 @@ func (r *DynamoComponentRequestReconciler) getDockerRegistry(ctx context.Context
if strings.Contains(dockerRegistryConfig.Server, "docker.io") { if strings.Contains(dockerRegistryConfig.Server, "docker.io") {
dynamoRepositoryURI = fmt.Sprintf("docker.io/%s", dynamoRepositoryName) dynamoRepositoryURI = fmt.Sprintf("docker.io/%s", dynamoRepositoryName)
} }
dynamoRepositoryInClusterURI := dynamoRepositoryURI
if dockerRegistryConfig.InClusterServer != "" { if DynamoComponent != nil && DynamoComponent.Spec.DockerConfigJSONSecretName != "" {
dynamoRepositoryInClusterURI = fmt.Sprintf("%s/%s", strings.TrimRight(dockerRegistryConfig.InClusterServer, "/"), dynamoRepositoryName) dockerRegistryConfig.SecretName = DynamoComponent.Spec.DockerConfigJSONSecretName
if strings.Contains(dockerRegistryConfig.InClusterServer, "docker.io") {
dynamoRepositoryInClusterURI = fmt.Sprintf("docker.io/%s", dynamoRepositoryName)
}
} }
dockerRegistry = schemas.DockerRegistrySchema{
Server: dockerRegistryConfig.Server, dockerRegistry = &schemas.DockerRegistrySchema{
Username: dockerRegistryConfig.Username, Server: dockerRegistryConfig.Server,
Password: dockerRegistryConfig.Password, Secure: dockerRegistryConfig.Secure,
Secure: dockerRegistryConfig.Secure, DynamoRepositoryURI: dynamoRepositoryURI,
DynamoRepositoryURI: dynamoRepositoryURI, SecretName: dockerRegistryConfig.SecretName,
DynamoRepositoryURIInCluster: dynamoRepositoryInClusterURI, }
err = r.RetrieveDockerRegistrySecret(ctx, dockerRegistryConfig.SecretName, DynamoComponent.Namespace, dockerRegistry)
if err != nil {
err = errors.Wrap(err, "retrieve docker registry secret")
return
} }
return return
...@@ -848,49 +691,45 @@ func isAddNamespacePrefix() bool { ...@@ -848,49 +691,45 @@ func isAddNamespacePrefix() bool {
return os.Getenv("ADD_NAMESPACE_PREFIX_TO_IMAGE_NAME") == trueStr return os.Getenv("ADD_NAMESPACE_PREFIX_TO_IMAGE_NAME") == trueStr
} }
func getDynamoComponentImagePrefix(dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest) string { func getDynamoComponentImagePrefix(DynamoComponent *nvidiacomv1alpha1.DynamoComponent) string {
if dynamoComponentRequest == nil { if DynamoComponent == nil {
return "" return ""
} }
prefix, exist := dynamoComponentRequest.Annotations[consts.KubeAnnotationDynamoComponentStorageNS] prefix, exist := DynamoComponent.Annotations[consts.KubeAnnotationDynamoComponentStorageNS]
if exist && prefix != "" { if exist && prefix != "" {
return fmt.Sprintf("%s.", prefix) return fmt.Sprintf("%s.", prefix)
} }
if isAddNamespacePrefix() { if isAddNamespacePrefix() {
return fmt.Sprintf("%s.", dynamoComponentRequest.Namespace) return fmt.Sprintf("%s.", DynamoComponent.Namespace)
} }
return "" return ""
} }
func getDynamoComponentImageName(dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest, dockerRegistry schemas.DockerRegistrySchema, dynamoComponentRepositoryName, dynamoComponentVersion string, inCluster bool) string { func getDynamoComponentImageName(DynamoComponent *nvidiacomv1alpha1.DynamoComponent, dockerRegistry schemas.DockerRegistrySchema, dynamoComponentRepositoryName, dynamoComponentVersion string) string {
if dynamoComponentRequest != nil && dynamoComponentRequest.Spec.Image != "" { if DynamoComponent != nil && DynamoComponent.Spec.Image != "" {
return dynamoComponentRequest.Spec.Image return DynamoComponent.Spec.Image
} }
var uri, tag string var uri, tag string
if inCluster { uri = dockerRegistry.DynamoRepositoryURI
uri = dockerRegistry.DynamoRepositoryURIInCluster
} else {
uri = dockerRegistry.DynamoRepositoryURI
}
tail := fmt.Sprintf("%s.%s", dynamoComponentRepositoryName, dynamoComponentVersion) tail := fmt.Sprintf("%s.%s", dynamoComponentRepositoryName, dynamoComponentVersion)
if isEstargzEnabled() { if isEstargzEnabled() {
tail += ".esgz" tail += ".esgz"
} }
tag = fmt.Sprintf("dynamo.%s%s", getDynamoComponentImagePrefix(dynamoComponentRequest), tail) tag = fmt.Sprintf("dynamo.%s%s", getDynamoComponentImagePrefix(DynamoComponent), tail)
if len(tag) > 128 { if len(tag) > 128 {
hashStr := hash(tail) hashStr := hash(tail)
tag = fmt.Sprintf("dynamo.%s%s", getDynamoComponentImagePrefix(dynamoComponentRequest), hashStr) tag = fmt.Sprintf("dynamo.%s%s", getDynamoComponentImagePrefix(DynamoComponent), hashStr)
if len(tag) > 128 { if len(tag) > 128 {
tag = fmt.Sprintf("dynamo.%s", hash(fmt.Sprintf("%s%s", getDynamoComponentImagePrefix(dynamoComponentRequest), tail)))[:128] tag = fmt.Sprintf("dynamo.%s", hash(fmt.Sprintf("%s%s", getDynamoComponentImagePrefix(DynamoComponent), tail)))[:128]
} }
} }
return fmt.Sprintf("%s:%s", uri, tag) return fmt.Sprintf("%s:%s", uri, tag)
} }
func checkImageExists(dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest, dockerRegistry schemas.DockerRegistrySchema, imageName string) (bool, error) { func checkImageExists(DynamoComponent *nvidiacomv1alpha1.DynamoComponent, dockerRegistry schemas.DockerRegistrySchema, imageName string) (bool, error) {
if dynamoComponentRequest.Annotations["nvidia.com/force-build-image"] == commonconsts.KubeLabelValueTrue { if DynamoComponent.Annotations["nvidia.com/force-build-image"] == commonconsts.KubeLabelValueTrue {
return false, nil return false, nil
} }
...@@ -930,72 +769,46 @@ type ImageInfo struct { ...@@ -930,72 +769,46 @@ type ImageInfo struct {
DockerRegistry schemas.DockerRegistrySchema DockerRegistry schemas.DockerRegistrySchema
DockerConfigJSONSecretName string DockerConfigJSONSecretName string
ImageName string ImageName string
InClusterImageName string
DockerRegistryInsecure bool DockerRegistryInsecure bool
} }
type GetImageInfoOption struct { type GetImageInfoOption struct {
DynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest DynamoComponent *nvidiacomv1alpha1.DynamoComponent
} }
//nolint:nakedret //nolint:nakedret
func (r *DynamoComponentRequestReconciler) getImageInfo(ctx context.Context, opt GetImageInfoOption) (imageInfo ImageInfo, err error) { func (r *DynamoComponentReconciler) getImageInfo(ctx context.Context, opt GetImageInfoOption) (imageInfo ImageInfo, err error) {
dynamoComponentRepositoryName, _, dynamoComponentVersion := xstrings.Partition(opt.DynamoComponentRequest.Spec.DynamoComponent, ":") dynamoComponentRepositoryName, _, dynamoComponentVersion := xstrings.Partition(opt.DynamoComponent.Spec.DynamoComponent, ":")
dockerRegistry, err := r.getDockerRegistry(ctx, opt.DynamoComponentRequest) dockerRegistry, err := r.getDockerRegistry(ctx, opt.DynamoComponent)
if err != nil { if err != nil {
err = errors.Wrap(err, "get docker registry") err = errors.Wrap(err, "get docker registry")
return return
} }
imageInfo.DockerRegistry = dockerRegistry imageInfo.DockerRegistry = *dockerRegistry
imageInfo.ImageName = getDynamoComponentImageName(opt.DynamoComponentRequest, dockerRegistry, dynamoComponentRepositoryName, dynamoComponentVersion, false) imageInfo.ImageName = getDynamoComponentImageName(opt.DynamoComponent, *dockerRegistry, dynamoComponentRepositoryName, dynamoComponentVersion)
imageInfo.InClusterImageName = getDynamoComponentImageName(opt.DynamoComponentRequest, dockerRegistry, dynamoComponentRepositoryName, dynamoComponentVersion, true)
imageInfo.DockerConfigJSONSecretName = opt.DynamoComponentRequest.Spec.DockerConfigJSONSecretName imageInfo.DockerConfigJSONSecretName = dockerRegistry.SecretName
imageInfo.DockerRegistryInsecure = opt.DynamoComponentRequest.Annotations[commonconsts.KubeAnnotationDynamoDockerRegistryInsecure] == "true"
if opt.DynamoComponentRequest.Spec.OCIRegistryInsecure != nil {
imageInfo.DockerRegistryInsecure = *opt.DynamoComponentRequest.Spec.OCIRegistryInsecure
}
if imageInfo.DockerConfigJSONSecretName == "" { imageInfo.DockerRegistryInsecure = opt.DynamoComponent.Annotations[commonconsts.KubeAnnotationDynamoDockerRegistryInsecure] == "true"
var dockerRegistryConf *commonconfig.DockerRegistryConfig
dockerRegistryConf, err = commonconfig.GetDockerRegistryConfig()
if err != nil {
err = errors.Wrap(err, "get docker registry")
return
}
imageInfo.DockerRegistryInsecure = !dockerRegistryConf.Secure
var dockerConfigSecret *corev1.Secret
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Making sure docker config secret %s in namespace %s", commonconsts.KubeSecretNameRegcred, opt.DynamoComponentRequest.Namespace)
dockerConfigSecret, err = r.makeSureDockerConfigJSONSecret(ctx, opt.DynamoComponentRequest.Namespace, dockerRegistryConf)
if err != nil {
err = errors.Wrap(err, "make sure docker config secret")
return
}
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Docker config secret %s in namespace %s is ready", commonconsts.KubeSecretNameRegcred, opt.DynamoComponentRequest.Namespace)
if dockerConfigSecret != nil {
imageInfo.DockerConfigJSONSecretName = dockerConfigSecret.Name
}
}
return return
} }
func (r *DynamoComponentRequestReconciler) getImageBuilderJobName() string { func (r *DynamoComponentReconciler) getImageBuilderJobName() string {
guid := xid.New() guid := xid.New()
return fmt.Sprintf("dynamo-image-builder-%s", guid.String()) return fmt.Sprintf("dynamo-image-builder-%s", guid.String())
} }
func (r *DynamoComponentRequestReconciler) getImageBuilderJobLabels(dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest) map[string]string { func (r *DynamoComponentReconciler) getImageBuilderJobLabels(DynamoComponent *nvidiacomv1alpha1.DynamoComponent) map[string]string {
return map[string]string{ return map[string]string{
commonconsts.KubeLabelDynamoComponentRequest: dynamoComponentRequest.Name, commonconsts.KubeLabelDynamoComponent: DynamoComponent.Name,
commonconsts.KubeLabelIsDynamoImageBuilder: "true", commonconsts.KubeLabelIsDynamoImageBuilder: "true",
} }
} }
func (r *DynamoComponentRequestReconciler) getImageBuilderPodLabels(dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest) map[string]string { func (r *DynamoComponentReconciler) getImageBuilderPodLabels(DynamoComponent *nvidiacomv1alpha1.DynamoComponent) map[string]string {
return map[string]string{ return map[string]string{
commonconsts.KubeLabelDynamoComponentRequest: dynamoComponentRequest.Name, commonconsts.KubeLabelDynamoComponent: DynamoComponent.Name,
commonconsts.KubeLabelIsDynamoImageBuilder: "true", commonconsts.KubeLabelIsDynamoImageBuilder: "true",
} }
} }
...@@ -1007,12 +820,12 @@ func hash(text string) string { ...@@ -1007,12 +820,12 @@ func hash(text string) string {
} }
type GenerateImageBuilderJobOption struct { type GenerateImageBuilderJobOption struct {
ImageInfo ImageInfo ImageInfo ImageInfo
DynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest DynamoComponent *nvidiacomv1alpha1.DynamoComponent
} }
//nolint:nakedret //nolint:nakedret
func (r *DynamoComponentRequestReconciler) generateImageBuilderJob(ctx context.Context, opt GenerateImageBuilderJobOption) (job *batchv1.Job, err error) { func (r *DynamoComponentReconciler) generateImageBuilderJob(ctx context.Context, opt GenerateImageBuilderJobOption) (job *batchv1.Job, err error) {
// nolint: gosimple // nolint: gosimple
podTemplateSpec, err := r.generateImageBuilderPodTemplateSpec(ctx, GenerateImageBuilderPodTemplateSpecOption(opt)) podTemplateSpec, err := r.generateImageBuilderPodTemplateSpec(ctx, GenerateImageBuilderPodTemplateSpecOption(opt))
if err != nil { if err != nil {
...@@ -1020,17 +833,17 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderJob(ctx context.C ...@@ -1020,17 +833,17 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderJob(ctx context.C
return return
} }
kubeAnnotations := make(map[string]string) kubeAnnotations := make(map[string]string)
hashStr, err := r.getHashStr(opt.DynamoComponentRequest) hashStr, err := r.getHashStr(opt.DynamoComponent)
if err != nil { if err != nil {
err = errors.Wrap(err, "failed to get hash string") err = errors.Wrap(err, "failed to get hash string")
return return
} }
kubeAnnotations[consts.KubeAnnotationDynamoComponentRequestHash] = hashStr kubeAnnotations[consts.KubeAnnotationDynamoComponentHash] = hashStr
job = &batchv1.Job{ job = &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: r.getImageBuilderJobName(), Name: r.getImageBuilderJobName(),
Namespace: opt.DynamoComponentRequest.Namespace, Namespace: opt.DynamoComponent.Namespace,
Labels: r.getImageBuilderJobLabels(opt.DynamoComponentRequest), Labels: r.getImageBuilderJobLabels(opt.DynamoComponent),
Annotations: kubeAnnotations, Annotations: kubeAnnotations,
}, },
Spec: batchv1.JobSpec{ Spec: batchv1.JobSpec{
...@@ -1052,7 +865,7 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderJob(ctx context.C ...@@ -1052,7 +865,7 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderJob(ctx context.C
Template: *podTemplateSpec, Template: *podTemplateSpec,
}, },
} }
err = ctrl.SetControllerReference(opt.DynamoComponentRequest, job, r.Scheme) err = ctrl.SetControllerReference(opt.DynamoComponent, job, r.Scheme)
if err != nil { if err != nil {
err = errors.Wrapf(err, "set controller reference for job %s", job.Name) err = errors.Wrapf(err, "set controller reference for job %s", job.Name)
return return
...@@ -1060,7 +873,7 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderJob(ctx context.C ...@@ -1060,7 +873,7 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderJob(ctx context.C
return return
} }
func injectPodAffinity(podSpec *corev1.PodSpec, dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest) { func injectPodAffinity(podSpec *corev1.PodSpec, DynamoComponent *nvidiacomv1alpha1.DynamoComponent) {
if podSpec.Affinity == nil { if podSpec.Affinity == nil {
podSpec.Affinity = &corev1.Affinity{} podSpec.Affinity = &corev1.Affinity{}
} }
...@@ -1074,7 +887,7 @@ func injectPodAffinity(podSpec *corev1.PodSpec, dynamoComponentRequest *nvidiaco ...@@ -1074,7 +887,7 @@ func injectPodAffinity(podSpec *corev1.PodSpec, dynamoComponentRequest *nvidiaco
PodAffinityTerm: corev1.PodAffinityTerm{ PodAffinityTerm: corev1.PodAffinityTerm{
LabelSelector: &metav1.LabelSelector{ LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{ MatchLabels: map[string]string{
commonconsts.KubeLabelDynamoComponentRequest: dynamoComponentRequest.Name, commonconsts.KubeLabelDynamoComponent: DynamoComponent.Name,
}, },
}, },
TopologyKey: corev1.LabelHostname, TopologyKey: corev1.LabelHostname,
...@@ -1088,16 +901,16 @@ const ModelSeederContainerName = "seeder" ...@@ -1088,16 +901,16 @@ const ModelSeederContainerName = "seeder"
const ModelSeederJobFailedExitCode = 42 const ModelSeederJobFailedExitCode = 42
type GenerateImageBuilderPodTemplateSpecOption struct { type GenerateImageBuilderPodTemplateSpecOption struct {
ImageInfo ImageInfo ImageInfo ImageInfo
DynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest DynamoComponent *nvidiacomv1alpha1.DynamoComponent
} }
//nolint:gocyclo,nakedret //nolint:gocyclo,nakedret
func (r *DynamoComponentRequestReconciler) generateImageBuilderPodTemplateSpec(ctx context.Context, opt GenerateImageBuilderPodTemplateSpecOption) (pod *corev1.PodTemplateSpec, err error) { func (r *DynamoComponentReconciler) generateImageBuilderPodTemplateSpec(ctx context.Context, opt GenerateImageBuilderPodTemplateSpecOption) (pod *corev1.PodTemplateSpec, err error) {
dynamoComponentRepositoryName, _, dynamoComponentVersion := xstrings.Partition(opt.DynamoComponentRequest.Spec.DynamoComponent, ":") dynamoComponentRepositoryName, _, dynamoComponentVersion := xstrings.Partition(opt.DynamoComponent.Spec.DynamoComponent, ":")
kubeLabels := r.getImageBuilderPodLabels(opt.DynamoComponentRequest) kubeLabels := r.getImageBuilderPodLabels(opt.DynamoComponent)
inClusterImageName := opt.ImageInfo.InClusterImageName imageName := opt.ImageInfo.ImageName
dockerConfigJSONSecretName := opt.ImageInfo.DockerConfigJSONSecretName dockerConfigJSONSecretName := opt.ImageInfo.DockerConfigJSONSecretName
...@@ -1151,7 +964,7 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderPodTemplateSpec(c ...@@ -1151,7 +964,7 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderPodTemplateSpec(c
} }
var dynamoComponent *schemas.DynamoComponent var dynamoComponent *schemas.DynamoComponent
dynamoComponentDownloadURL := opt.DynamoComponentRequest.Spec.DownloadURL dynamoComponentDownloadURL := opt.DynamoComponent.Spec.DownloadURL
if dynamoComponentDownloadURL == "" { if dynamoComponentDownloadURL == "" {
var apiStoreClient *apiStoreClient.ApiStoreClient var apiStoreClient *apiStoreClient.ApiStoreClient
...@@ -1168,23 +981,23 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderPodTemplateSpec(c ...@@ -1168,23 +981,23 @@ func (r *DynamoComponentRequestReconciler) generateImageBuilderPodTemplateSpec(c
return return
} }
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Getting dynamoComponent %s from api store service", opt.DynamoComponentRequest.Spec.DynamoComponent) r.Recorder.Eventf(opt.DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Getting dynamoComponent %s from api store service", opt.DynamoComponent.Spec.DynamoComponent)
dynamoComponent, err = apiStoreClient.GetDynamoComponent(ctx, dynamoComponentRepositoryName, dynamoComponentVersion) dynamoComponent, err = apiStoreClient.GetDynamoComponent(ctx, dynamoComponentRepositoryName, dynamoComponentVersion)
if err != nil { if err != nil {
err = errors.Wrap(err, "get dynamoComponent") err = errors.Wrap(err, "get dynamoComponent")
return return
} }
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Got dynamoComponent %s from api store service", opt.DynamoComponentRequest.Spec.DynamoComponent) r.Recorder.Eventf(opt.DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Got dynamoComponent %s from api store service", opt.DynamoComponent.Spec.DynamoComponent)
if dynamoComponent.TransmissionStrategy != nil && *dynamoComponent.TransmissionStrategy == schemas.TransmissionStrategyPresignedURL { if dynamoComponent.TransmissionStrategy != nil && *dynamoComponent.TransmissionStrategy == schemas.TransmissionStrategyPresignedURL {
var dynamoComponent_ *schemas.DynamoComponent var dynamoComponent_ *schemas.DynamoComponent
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Getting presigned url for dynamoComponent %s from api store service", opt.DynamoComponentRequest.Spec.DynamoComponent) r.Recorder.Eventf(opt.DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Getting presigned url for dynamoComponent %s from api store service", opt.DynamoComponent.Spec.DynamoComponent)
dynamoComponent_, err = apiStoreClient.PresignDynamoComponentDownloadURL(ctx, dynamoComponentRepositoryName, dynamoComponentVersion) dynamoComponent_, err = apiStoreClient.PresignDynamoComponentDownloadURL(ctx, dynamoComponentRepositoryName, dynamoComponentVersion)
if err != nil { if err != nil {
err = errors.Wrap(err, "presign dynamoComponent download url") err = errors.Wrap(err, "presign dynamoComponent download url")
return return
} }
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Got presigned url for dynamoComponent %s from api store service", opt.DynamoComponentRequest.Spec.DynamoComponent) r.Recorder.Eventf(opt.DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Got presigned url for dynamoComponent %s from api store service", opt.DynamoComponent.Spec.DynamoComponent)
dynamoComponentDownloadURL = dynamoComponent_.PresignedDownloadUrl dynamoComponentDownloadURL = dynamoComponent_.PresignedDownloadUrl
} else { } else {
dynamoComponentDownloadURL = fmt.Sprintf("%s/api/v1/dynamo_nims/%s/versions/%s/download", apiStoreConf.Endpoint, dynamoComponentRepositoryName, dynamoComponentVersion) dynamoComponentDownloadURL = fmt.Sprintf("%s/api/v1/dynamo_nims/%s/versions/%s/download", apiStoreConf.Endpoint, dynamoComponentRepositoryName, dynamoComponentVersion)
...@@ -1256,7 +1069,7 @@ echo "Done" ...@@ -1256,7 +1069,7 @@ echo "Done"
}, },
} }
downloaderContainerEnvFrom := opt.DynamoComponentRequest.Spec.DownloaderContainerEnvFrom downloaderContainerEnvFrom := opt.DynamoComponent.Spec.DownloaderContainerEnvFrom
initContainers := []corev1.Container{ initContainers := []corev1.Container{
{ {
...@@ -1295,7 +1108,7 @@ echo "Done" ...@@ -1295,7 +1108,7 @@ echo "Done"
} }
configCmName := "dynamo-image-builder-config" configCmName := "dynamo-image-builder-config"
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Getting configmap %s from namespace %s", configCmName, configNamespace) r.Recorder.Eventf(opt.DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Getting configmap %s from namespace %s", configCmName, configNamespace)
configCm := &corev1.ConfigMap{} configCm := &corev1.ConfigMap{}
err = r.Get(ctx, types.NamespacedName{Name: configCmName, Namespace: configNamespace}, configCm) err = r.Get(ctx, types.NamespacedName{Name: configCmName, Namespace: configNamespace}, configCm)
configCmIsNotFound := k8serrors.IsNotFound(err) configCmIsNotFound := k8serrors.IsNotFound(err)
...@@ -1306,7 +1119,7 @@ echo "Done" ...@@ -1306,7 +1119,7 @@ echo "Done"
err = nil // nolint: ineffassign err = nil // nolint: ineffassign
if !configCmIsNotFound { if !configCmIsNotFound {
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Configmap %s is got from namespace %s", configCmName, configNamespace) r.Recorder.Eventf(opt.DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Configmap %s is got from namespace %s", configCmName, configNamespace)
globalExtraPodMetadata = &dynamoCommon.ExtraPodMetadata{} globalExtraPodMetadata = &dynamoCommon.ExtraPodMetadata{}
...@@ -1367,15 +1180,15 @@ echo "Done" ...@@ -1367,15 +1180,15 @@ echo "Done"
} }
logrus.Info("passed in builder args: ", builderArgs) logrus.Info("passed in builder args: ", builderArgs)
} else { } else {
r.Recorder.Eventf(opt.DynamoComponentRequest, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Configmap %s is not found in namespace %s", configCmName, configNamespace) r.Recorder.Eventf(opt.DynamoComponent, corev1.EventTypeNormal, "GenerateImageBuilderPod", "Configmap %s is not found in namespace %s", configCmName, configNamespace)
} }
if buildArgs == nil { if buildArgs == nil {
buildArgs = make([]string, 0) buildArgs = make([]string, 0)
} }
if opt.DynamoComponentRequest.Spec.BuildArgs != nil { if opt.DynamoComponent.Spec.BuildArgs != nil {
buildArgs = append(buildArgs, opt.DynamoComponentRequest.Spec.BuildArgs...) buildArgs = append(buildArgs, opt.DynamoComponent.Spec.BuildArgs...)
} }
dockerFilePath := "/workspace/buildcontext/env/docker/Dockerfile" dockerFilePath := "/workspace/buildcontext/env/docker/Dockerfile"
...@@ -1394,11 +1207,11 @@ echo "Done" ...@@ -1394,11 +1207,11 @@ echo "Done"
kanikoCacheRepo := os.Getenv("KANIKO_CACHE_REPO") kanikoCacheRepo := os.Getenv("KANIKO_CACHE_REPO")
if kanikoCacheRepo == "" { if kanikoCacheRepo == "" {
kanikoCacheRepo = opt.ImageInfo.DockerRegistry.DynamoRepositoryURIInCluster kanikoCacheRepo = opt.ImageInfo.DockerRegistry.DynamoRepositoryURI
} }
kubeAnnotations := make(map[string]string) kubeAnnotations := make(map[string]string)
kubeAnnotations[consts.KubeAnnotationDynamoComponentRequestImageBuiderHash] = opt.DynamoComponentRequest.Annotations[consts.KubeAnnotationDynamoComponentRequestImageBuiderHash] kubeAnnotations[consts.KubeAnnotationDynamoComponentImageBuiderHash] = opt.DynamoComponent.Annotations[consts.KubeAnnotationDynamoComponentImageBuiderHash]
command := []string{ command := []string{
"/kaniko/executor", "/kaniko/executor",
...@@ -1414,7 +1227,7 @@ echo "Done" ...@@ -1414,7 +1227,7 @@ echo "Done"
"--compression-level=-7", "--compression-level=-7",
fmt.Sprintf("--dockerfile=%s", dockerFilePath), fmt.Sprintf("--dockerfile=%s", dockerFilePath),
fmt.Sprintf("--insecure=%v", dockerRegistryInsecure), fmt.Sprintf("--insecure=%v", dockerRegistryInsecure),
fmt.Sprintf("--destination=%s", inClusterImageName), fmt.Sprintf("--destination=%s", imageName),
} }
kanikoSnapshotMode := os.Getenv("KANIKO_SNAPSHOT_MODE") kanikoSnapshotMode := os.Getenv("KANIKO_SNAPSHOT_MODE")
...@@ -1444,7 +1257,7 @@ echo "Done" ...@@ -1444,7 +1257,7 @@ echo "Done"
isBuildkit := buildEngine == DynamoComponentImageBuildEngineBuildkit || buildEngine == DynamoComponentImageBuildEngineBuildkitRootless isBuildkit := buildEngine == DynamoComponentImageBuildEngineBuildkit || buildEngine == DynamoComponentImageBuildEngineBuildkitRootless
if isBuildkit { if isBuildkit {
output := fmt.Sprintf("type=image,name=%s,push=true,registry.insecure=%v", inClusterImageName, dockerRegistryInsecure) output := fmt.Sprintf("type=image,name=%s,push=true,registry.insecure=%v", imageName, dockerRegistryInsecure)
buildkitdFlags := []string{} buildkitdFlags := []string{}
if !privileged { if !privileged {
buildkitdFlags = append(buildkitdFlags, "--oci-worker-no-process-sandbox") buildkitdFlags = append(buildkitdFlags, "--oci-worker-no-process-sandbox")
...@@ -1540,8 +1353,8 @@ echo "Done" ...@@ -1540,8 +1353,8 @@ echo "Done"
container.Resources = *globalDefaultImageBuilderContainerResources container.Resources = *globalDefaultImageBuilderContainerResources
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderContainerResources != nil { if opt.DynamoComponent.Spec.ImageBuilderContainerResources != nil {
container.Resources = *opt.DynamoComponentRequest.Spec.ImageBuilderContainerResources container.Resources = *opt.DynamoComponent.Spec.ImageBuilderContainerResources
} }
containers = append(containers, container) containers = append(containers, container)
...@@ -1569,12 +1382,12 @@ echo "Done" ...@@ -1569,12 +1382,12 @@ echo "Done"
} }
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodMetadata != nil { if opt.DynamoComponent.Spec.ImageBuilderExtraPodMetadata != nil {
for k, v := range opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodMetadata.Annotations { for k, v := range opt.DynamoComponent.Spec.ImageBuilderExtraPodMetadata.Annotations {
pod.Annotations[k] = v pod.Annotations[k] = v
} }
for k, v := range opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodMetadata.Labels { for k, v := range opt.DynamoComponent.Spec.ImageBuilderExtraPodMetadata.Labels {
pod.Labels[k] = v pod.Labels[k] = v
} }
} }
...@@ -1589,45 +1402,45 @@ echo "Done" ...@@ -1589,45 +1402,45 @@ echo "Done"
pod.Spec.ServiceAccountName = globalExtraPodSpec.ServiceAccountName pod.Spec.ServiceAccountName = globalExtraPodSpec.ServiceAccountName
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec != nil { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec != nil {
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.PriorityClassName != "" { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.PriorityClassName != "" {
pod.Spec.PriorityClassName = opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.PriorityClassName pod.Spec.PriorityClassName = opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.PriorityClassName
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.SchedulerName != "" { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.SchedulerName != "" {
pod.Spec.SchedulerName = opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.SchedulerName pod.Spec.SchedulerName = opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.SchedulerName
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.NodeSelector != nil { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.NodeSelector != nil {
pod.Spec.NodeSelector = opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.NodeSelector pod.Spec.NodeSelector = opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.NodeSelector
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.Affinity != nil { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.Affinity != nil {
pod.Spec.Affinity = opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.Affinity pod.Spec.Affinity = opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.Affinity
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.Tolerations != nil { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.Tolerations != nil {
pod.Spec.Tolerations = opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.Tolerations pod.Spec.Tolerations = opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.Tolerations
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.TopologySpreadConstraints != nil { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.TopologySpreadConstraints != nil {
pod.Spec.TopologySpreadConstraints = opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.TopologySpreadConstraints pod.Spec.TopologySpreadConstraints = opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.TopologySpreadConstraints
} }
if opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.ServiceAccountName != "" { if opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.ServiceAccountName != "" {
pod.Spec.ServiceAccountName = opt.DynamoComponentRequest.Spec.ImageBuilderExtraPodSpec.ServiceAccountName pod.Spec.ServiceAccountName = opt.DynamoComponent.Spec.ImageBuilderExtraPodSpec.ServiceAccountName
} }
} }
injectPodAffinity(&pod.Spec, opt.DynamoComponentRequest) injectPodAffinity(&pod.Spec, opt.DynamoComponent)
if pod.Spec.ServiceAccountName == "" { if pod.Spec.ServiceAccountName == "" {
serviceAccounts := &corev1.ServiceAccountList{} serviceAccounts := &corev1.ServiceAccountList{}
err = r.List(ctx, serviceAccounts, client.InNamespace(opt.DynamoComponentRequest.Namespace), client.MatchingLabels{ err = r.List(ctx, serviceAccounts, client.InNamespace(opt.DynamoComponent.Namespace), client.MatchingLabels{
commonconsts.KubeLabelDynamoImageBuilderPod: commonconsts.KubeLabelValueTrue, commonconsts.KubeLabelDynamoImageBuilderPod: commonconsts.KubeLabelValueTrue,
}) })
if err != nil { if err != nil {
err = errors.Wrapf(err, "failed to list service accounts in namespace %s", opt.DynamoComponentRequest.Namespace) err = errors.Wrapf(err, "failed to list service accounts in namespace %s", opt.DynamoComponent.Namespace)
return return
} }
if len(serviceAccounts.Items) > 0 { if len(serviceAccounts.Items) > 0 {
...@@ -1642,7 +1455,7 @@ echo "Done" ...@@ -1642,7 +1455,7 @@ echo "Done"
if globalExtraContainerEnv != nil { if globalExtraContainerEnv != nil {
env = append(env, globalExtraContainerEnv...) env = append(env, globalExtraContainerEnv...)
} }
env = append(env, opt.DynamoComponentRequest.Spec.ImageBuilderExtraContainerEnv...) env = append(env, opt.DynamoComponent.Spec.ImageBuilderExtraContainerEnv...)
pod.Spec.InitContainers[i].Env = env pod.Spec.InitContainers[i].Env = env
} }
for i, c := range pod.Spec.Containers { for i, c := range pod.Spec.Containers {
...@@ -1650,26 +1463,26 @@ echo "Done" ...@@ -1650,26 +1463,26 @@ echo "Done"
if globalExtraContainerEnv != nil { if globalExtraContainerEnv != nil {
env = append(env, globalExtraContainerEnv...) env = append(env, globalExtraContainerEnv...)
} }
env = append(env, opt.DynamoComponentRequest.Spec.ImageBuilderExtraContainerEnv...) env = append(env, opt.DynamoComponent.Spec.ImageBuilderExtraContainerEnv...)
pod.Spec.Containers[i].Env = env pod.Spec.Containers[i].Env = env
} }
return return
} }
func (r *DynamoComponentRequestReconciler) getHashStr(dynamoComponentRequest *nvidiacomv1alpha1.DynamoComponentRequest) (string, error) { func (r *DynamoComponentReconciler) getHashStr(DynamoComponent *nvidiacomv1alpha1.DynamoComponent) (string, error) {
var hash uint64 var hash uint64
hash, err := hashstructure.Hash(struct { hash, err := hashstructure.Hash(struct {
Spec nvidiacomv1alpha1.DynamoComponentRequestSpec Spec nvidiacomv1alpha1.DynamoComponentSpec
Labels map[string]string Labels map[string]string
Annotations map[string]string Annotations map[string]string
}{ }{
Spec: dynamoComponentRequest.Spec, Spec: DynamoComponent.Spec,
Labels: dynamoComponentRequest.Labels, Labels: DynamoComponent.Labels,
Annotations: dynamoComponentRequest.Annotations, Annotations: DynamoComponent.Annotations,
}, hashstructure.FormatV2, nil) }, hashstructure.FormatV2, nil)
if err != nil { if err != nil {
err = errors.Wrap(err, "get dynamoComponentRequest CR spec hash") err = errors.Wrap(err, "get DynamoComponent CR spec hash")
return "", err return "", err
} }
hashStr := strconv.FormatUint(hash, 10) hashStr := strconv.FormatUint(hash, 10)
...@@ -1681,13 +1494,13 @@ const ( ...@@ -1681,13 +1494,13 @@ const (
) )
// SetupWithManager sets up the controller with the Manager. // SetupWithManager sets up the controller with the Manager.
func (r *DynamoComponentRequestReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *DynamoComponentReconciler) SetupWithManager(mgr ctrl.Manager) error {
err := ctrl.NewControllerManagedBy(mgr). err := ctrl.NewControllerManagedBy(mgr).
For(&nvidiacomv1alpha1.DynamoComponentRequest{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). For(&nvidiacomv1alpha1.DynamoComponent{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Owns(&nvidiacomv1alpha1.DynamoComponent{}). Owns(&nvidiacomv1alpha1.DynamoComponent{}).
Owns(&batchv1.Job{}). Owns(&batchv1.Job{}).
WithEventFilter(controller_common.EphemeralDeploymentEventFilter(r.Config)). WithEventFilter(controller_common.EphemeralDeploymentEventFilter(r.Config)).
Complete(r) Complete(r)
return errors.Wrap(err, "failed to setup DynamoComponentRequest controller") return errors.Wrap(err, "failed to setup DynamoComponent controller")
} }
...@@ -39,6 +39,7 @@ import ( ...@@ -39,6 +39,7 @@ import (
dynamoCommon "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/dynamo/common" dynamoCommon "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/dynamo/common"
"github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/dynamo/schemas" "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/dynamo/schemas"
"github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/v1alpha1" "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/api/v1alpha1"
"github.com/ai-dynamo/dynamo/deploy/dynamo/operator/internal/config"
commonconsts "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/internal/consts" commonconsts "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/internal/consts"
"github.com/ai-dynamo/dynamo/deploy/dynamo/operator/internal/controller_common" "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/internal/controller_common"
commonController "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/internal/controller_common" commonController "github.com/ai-dynamo/dynamo/deploy/dynamo/operator/internal/controller_common"
...@@ -60,10 +61,8 @@ import ( ...@@ -60,10 +61,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/apiutil" "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
) )
const ( const (
...@@ -161,7 +160,7 @@ func (r *DynamoComponentDeploymentReconciler) Reconcile(ctx context.Context, req ...@@ -161,7 +160,7 @@ func (r *DynamoComponentDeploymentReconciler) Reconcile(ctx context.Context, req
Message: "Starting to reconcile DynamoComponentDeployment", Message: "Starting to reconcile DynamoComponentDeployment",
}, },
metav1.Condition{ metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentFound, Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentReady,
Status: metav1.ConditionUnknown, Status: metav1.ConditionUnknown,
Reason: "Reconciling", Reason: "Reconciling",
Message: "Starting to reconcile DynamoComponentDeployment", Message: "Starting to reconcile DynamoComponentDeployment",
...@@ -191,135 +190,48 @@ func (r *DynamoComponentDeploymentReconciler) Reconcile(ctx context.Context, req ...@@ -191,135 +190,48 @@ func (r *DynamoComponentDeploymentReconciler) Reconcile(ctx context.Context, req
} }
}() }()
dynamoComponentFoundCondition := meta.FindStatusCondition(dynamoComponentDeployment.Status.Conditions, v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentFound) // retrieve the dynamo component
if dynamoComponentFoundCondition != nil && dynamoComponentFoundCondition.Status == metav1.ConditionUnknown {
logs.Info(fmt.Sprintf("Getting Dynamo Component %s", dynamoComponentDeployment.Spec.DynamoComponent))
r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeNormal, "GetDynamoComponent", "Getting Dynamo Component %s", dynamoComponentDeployment.Spec.DynamoComponent)
}
dynamoComponentRequest := &v1alpha1.DynamoComponentRequest{}
dynamoComponentCR := &v1alpha1.DynamoComponent{} dynamoComponentCR := &v1alpha1.DynamoComponent{}
err = r.Get(ctx, types.NamespacedName{ err = r.Get(ctx, types.NamespacedName{Name: getK8sName(dynamoComponentDeployment.Spec.DynamoComponent), Namespace: dynamoComponentDeployment.Namespace}, dynamoComponentCR)
Namespace: dynamoComponentDeployment.Namespace, if err != nil {
Name: getK8sName(dynamoComponentDeployment.Spec.DynamoComponent), logs.Error(err, "Failed to get DynamoComponent")
}, dynamoComponentCR)
dynamoComponentIsNotFound := k8serrors.IsNotFound(err)
if err != nil && !dynamoComponentIsNotFound {
err = errors.Wrapf(err, "get DynamoComponent %s/%s", dynamoComponentDeployment.Namespace, dynamoComponentDeployment.Spec.DynamoComponent)
return return
} }
if dynamoComponentIsNotFound {
if dynamoComponentFoundCondition != nil && dynamoComponentFoundCondition.Status == metav1.ConditionUnknown { // check if the component is ready
logs.Info(fmt.Sprintf("DynamoComponent %s not found", dynamoComponentDeployment.Spec.DynamoComponent)) if dynamoComponentCR.IsReady() {
r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeNormal, "GetDynamoComponent", "DynamoComponent %s not found", dynamoComponentDeployment.Spec.DynamoComponent) logs.Info(fmt.Sprintf("DynamoComponent %s ready", dynamoComponentDeployment.Spec.DynamoComponent))
} r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeNormal, "GetDynamoComponent", "DynamoComponent %s is ready", dynamoComponentDeployment.Spec.DynamoComponent)
dynamoComponentDeployment, err = r.setStatusConditions(ctx, req, dynamoComponentDeployment, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentFound, Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentReady,
Status: metav1.ConditionFalse, Status: metav1.ConditionTrue,
Reason: "Reconciling", Reason: "Reconciling",
Message: "DynamoComponent not found", Message: "DynamoComponent is ready",
}, },
) )
if err != nil { if err != nil {
return return
} }
dynamoComponentRequestFoundCondition := meta.FindStatusCondition(dynamoComponentDeployment.Status.Conditions, v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentRequestFound) } else {
if dynamoComponentRequestFoundCondition == nil || dynamoComponentRequestFoundCondition.Status != metav1.ConditionUnknown { logs.Info(fmt.Sprintf("DynamoComponent %s not ready", dynamoComponentDeployment.Spec.DynamoComponent))
dynamoComponentDeployment, err = r.setStatusConditions(ctx, req, r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeWarning, "GetDynamoComponent", "DynamoComponent %s is not ready", dynamoComponentDeployment.Spec.DynamoComponent)
metav1.Condition{ _, err_ := r.setStatusConditions(ctx, req,
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentRequestFound,
Status: metav1.ConditionUnknown,
Reason: "Reconciling",
Message: "DynamoComponent not found",
},
)
if err != nil {
return
}
}
if dynamoComponentRequestFoundCondition != nil && dynamoComponentRequestFoundCondition.Status == metav1.ConditionUnknown {
r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeNormal, "GetDynamoComponentRequest", "Getting DynamoComponentRequest %s", dynamoComponentDeployment.Spec.DynamoComponent)
}
err = r.Get(ctx, types.NamespacedName{
Namespace: dynamoComponentDeployment.Namespace,
Name: getK8sName(dynamoComponentDeployment.Spec.DynamoComponent),
}, dynamoComponentRequest)
if err != nil {
err = errors.Wrapf(err, "get DynamoComponentRequest %s/%s", dynamoComponentDeployment.Namespace, dynamoComponentDeployment.Spec.DynamoComponent)
dynamoComponentDeployment, err = r.setStatusConditions(ctx, req,
metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentFound,
Status: metav1.ConditionFalse,
Reason: "Reconciling",
Message: err.Error(),
},
metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentRequestFound,
Status: metav1.ConditionFalse,
Reason: "Reconciling",
Message: err.Error(),
},
)
if err != nil {
return
}
}
if dynamoComponentRequestFoundCondition != nil && dynamoComponentRequestFoundCondition.Status == metav1.ConditionUnknown {
logs.Info(fmt.Sprintf("DynamoComponentRequest %s found", dynamoComponentDeployment.Spec.DynamoComponent))
r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeNormal, "GetDynamoComponentRequest", "DynamoComponentRequest %s is found and waiting for its dynamoComponent to be provided", dynamoComponentDeployment.Spec.DynamoComponent)
}
dynamoComponentDeployment, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentRequestFound, Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentReady,
Status: metav1.ConditionTrue, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: "DynamoComponent not found", Message: "DynamoComponent not ready",
}, },
)
if err != nil {
return
}
dynamoComponentRequestAvailableCondition := meta.FindStatusCondition(dynamoComponentRequest.Status.Conditions, v1alpha1.DynamoGraphDeploymentConditionTypeAvailable)
if dynamoComponentRequestAvailableCondition != nil && dynamoComponentRequestAvailableCondition.Status == metav1.ConditionFalse {
err = errors.Errorf("DynamoComponentRequest %s/%s is not available: %s", dynamoComponentRequest.Namespace, dynamoComponentRequest.Name, dynamoComponentRequestAvailableCondition.Message)
r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeWarning, "GetDynamoComponentRequest", err.Error())
_, err_ := r.setStatusConditions(ctx, req,
metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentFound,
Status: metav1.ConditionFalse,
Reason: "Reconciling",
Message: err.Error(),
},
metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeAvailable,
Status: metav1.ConditionFalse,
Reason: "Reconciling",
Message: err.Error(),
},
)
if err_ != nil {
err = err_
return
}
return
}
return
} else {
if dynamoComponentFoundCondition != nil && dynamoComponentFoundCondition.Status != metav1.ConditionTrue {
logs.Info(fmt.Sprintf("DynamoComponent %s found", dynamoComponentDeployment.Spec.DynamoComponent))
r.Recorder.Eventf(dynamoComponentDeployment, corev1.EventTypeNormal, "GetDynamoComponent", "DynamoComponent %s is found", dynamoComponentDeployment.Spec.DynamoComponent)
}
dynamoComponentDeployment, err = r.setStatusConditions(ctx, req,
metav1.Condition{ metav1.Condition{
Type: v1alpha1.DynamoGraphDeploymentConditionTypeDynamoComponentFound, Type: v1alpha1.DynamoGraphDeploymentConditionTypeAvailable,
Status: metav1.ConditionTrue, Status: metav1.ConditionFalse,
Reason: "Reconciling", Reason: "Reconciling",
Message: "DynamoComponent found", Message: "DynamoComponent not ready",
}, },
) )
if err != nil { err = err_
return return
}
} }
modified := false modified := false
...@@ -1291,7 +1203,10 @@ func (r *DynamoComponentDeploymentReconciler) generatePodTemplateSpec(ctx contex ...@@ -1291,7 +1203,10 @@ func (r *DynamoComponentDeploymentReconciler) generatePodTemplateSpec(ctx contex
}) })
} }
imageName := opt.dynamoComponent.Spec.Image imageName := opt.dynamoComponent.GetImage()
if imageName == "" {
return nil, errors.Errorf("image is not ready for component %s", opt.dynamoComponent.Name)
}
var securityContext *corev1.SecurityContext var securityContext *corev1.SecurityContext
var mainContainerSecurityContext *corev1.SecurityContext var mainContainerSecurityContext *corev1.SecurityContext
...@@ -1417,7 +1332,17 @@ func (r *DynamoComponentDeploymentReconciler) generatePodTemplateSpec(ctx contex ...@@ -1417,7 +1332,17 @@ func (r *DynamoComponentDeploymentReconciler) generatePodTemplateSpec(ctx contex
Volumes: volumes, Volumes: volumes,
} }
podSpec.ImagePullSecrets = opt.dynamoComponent.Spec.ImagePullSecrets podSpec.ImagePullSecrets = []corev1.LocalObjectReference{
{
Name: config.GetDockerRegistryConfig().SecretName,
},
}
if opt.dynamoComponent.Spec.DockerConfigJSONSecretName != "" {
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, corev1.LocalObjectReference{
Name: opt.dynamoComponent.Spec.DockerConfigJSONSecretName,
})
}
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, opt.dynamoComponent.Spec.ImagePullSecrets...)
extraPodMetadata := opt.dynamoComponentDeployment.Spec.ExtraPodMetadata extraPodMetadata := opt.dynamoComponentDeployment.Spec.ExtraPodMetadata
...@@ -1669,68 +1594,7 @@ func (r *DynamoComponentDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) ...@@ -1669,68 +1594,7 @@ func (r *DynamoComponentDeploymentReconciler) SetupWithManager(mgr ctrl.Manager)
Owns(&corev1.Service{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Owns(&corev1.Service{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Owns(&networkingv1.Ingress{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Owns(&networkingv1.Ingress{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Owns(&corev1.PersistentVolumeClaim{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Owns(&corev1.PersistentVolumeClaim{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Watches(&v1alpha1.DynamoComponentRequest{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, dynamoComponentRequest client.Object) []reconcile.Request { WithEventFilter(controller_common.EphemeralDeploymentEventFilter(r.Config))
reqs := make([]reconcile.Request, 0)
logs := log.Log.WithValues("func", "Watches", "kind", "DynamoComponentRequest", "name", dynamoComponentRequest.GetName(), "namespace", dynamoComponentRequest.GetNamespace())
logs.Info("Triggering reconciliation for DynamoComponentRequest", "DynamoComponentRequestName", dynamoComponentRequest.GetName(), "Namespace", dynamoComponentRequest.GetNamespace())
dynamoComponent := &v1alpha1.DynamoComponent{}
err := r.Get(context.Background(), types.NamespacedName{
Name: dynamoComponentRequest.GetName(),
Namespace: dynamoComponentRequest.GetNamespace(),
}, dynamoComponent)
dynamoComponentIsNotFound := k8serrors.IsNotFound(err)
if err != nil && !dynamoComponentIsNotFound {
logs.Info("Failed to get DynamoComponent", "name", dynamoComponentRequest.GetName(), "namespace", dynamoComponentRequest.GetNamespace(), "error", err)
return reqs
}
if !dynamoComponentIsNotFound {
logs.Info("DynamoComponent found, skipping enqueue as it's already present", "DynamoComponentName", dynamoComponentRequest.GetName())
return reqs
}
dynamoComponentDeployments := &v1alpha1.DynamoComponentDeploymentList{}
err = r.List(context.Background(), dynamoComponentDeployments, &client.ListOptions{
Namespace: dynamoComponentRequest.GetNamespace(),
})
if err != nil {
logs.Info("Failed to list DynamoComponentDeployments", "Namespace", dynamoComponentRequest.GetNamespace(), "error", err)
return reqs
}
for _, dynamoComponentDeployment := range dynamoComponentDeployments.Items {
dynamoComponentDeployment := dynamoComponentDeployment
if getK8sName(dynamoComponentDeployment.Spec.DynamoComponent) == dynamoComponentRequest.GetName() {
reqs = append(reqs, reconcile.Request{
NamespacedName: client.ObjectKeyFromObject(&dynamoComponentDeployment),
})
}
}
// Log the list of DynamoComponentDeployments being enqueued for reconciliation
logs.Info("Enqueuing DynamoComponentDeployments for reconciliation", "ReconcileRequests", reqs)
return reqs
})).WithEventFilter(controller_common.EphemeralDeploymentEventFilter(r.Config)).
Watches(&v1alpha1.DynamoComponent{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, dynamoComponent client.Object) []reconcile.Request {
logs := log.Log.WithValues("func", "Watches", "kind", "DynamoComponent", "name", dynamoComponent.GetName(), "namespace", dynamoComponent.GetNamespace())
logs.Info("Triggering reconciliation for DynamoComponent", "DynamoComponentName", dynamoComponent.GetName(), "Namespace", dynamoComponent.GetNamespace())
dynamoComponentDeployments := &v1alpha1.DynamoComponentDeploymentList{}
err := r.List(context.Background(), dynamoComponentDeployments, &client.ListOptions{
Namespace: dynamoComponent.GetNamespace(),
})
if err != nil {
logs.Info("Failed to list DynamoComponentDeployments", "Namespace", dynamoComponent.GetNamespace(), "error", err)
return []reconcile.Request{}
}
reqs := make([]reconcile.Request, 0)
for _, dynamoComponentDeployment := range dynamoComponentDeployments.Items {
dynamoComponentDeployment := dynamoComponentDeployment
if getK8sName(dynamoComponentDeployment.Spec.DynamoComponent) == dynamoComponent.GetName() {
reqs = append(reqs, reconcile.Request{
NamespacedName: client.ObjectKeyFromObject(&dynamoComponentDeployment),
})
}
}
// Log the list of DynamoComponentDeployments being enqueued for reconciliation
logs.Info("Enqueuing DynamoComponentDeployments for reconciliation", "ReconcileRequests", reqs)
return reqs
}))
if r.UseVirtualService { if r.UseVirtualService {
m.Owns(&networkingv1beta1.VirtualService{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})) m.Owns(&networkingv1beta1.VirtualService{}, builder.WithPredicates(predicate.GenerationChangedPredicate{}))
......
...@@ -20,13 +20,11 @@ package controller ...@@ -20,13 +20,11 @@ package controller
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"dario.cat/mergo" "dario.cat/mergo"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/builder"
...@@ -156,26 +154,33 @@ func (r *DynamoGraphDeploymentReconciler) Reconcile(ctx context.Context, req ctr ...@@ -156,26 +154,33 @@ func (r *DynamoGraphDeploymentReconciler) Reconcile(ctx context.Context, req ctr
} }
} }
// reconcile the dynamoComponentRequest // reconcile the dynamoComponent
// for now we use the same component for all the services and we differentiate them by the service name when launching the component // for now we use the same component for all the services and we differentiate them by the service name when launching the component
dynamoComponentRequest := &nvidiacomv1alpha1.DynamoComponentRequest{ dynamoComponent := &nvidiacomv1alpha1.DynamoComponent{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: strings.ReplaceAll(dynamoDeployment.Spec.DynamoGraph, ":", "--"), Name: getK8sName(dynamoDeployment.Spec.DynamoGraph),
Namespace: dynamoDeployment.Namespace, Namespace: dynamoDeployment.Namespace,
}, },
Spec: nvidiacomv1alpha1.DynamoComponentRequestSpec{ Spec: nvidiacomv1alpha1.DynamoComponentSpec{
DynamoComponent: dynamoDeployment.Spec.DynamoGraph, DynamoComponent: dynamoDeployment.Spec.DynamoGraph,
}, },
} }
if err := ctrl.SetControllerReference(dynamoDeployment, dynamoComponentRequest, r.Scheme); err != nil { if err := ctrl.SetControllerReference(dynamoDeployment, dynamoComponent, r.Scheme); err != nil {
reason = "failed_to_set_the_controller_reference_for_the_DynamoComponentRequest" reason = "failed_to_set_the_controller_reference_for_the_DynamoComponent"
return ctrl.Result{}, err return ctrl.Result{}, err
} }
_, err = commonController.SyncResource(ctx, r.Client, dynamoComponentRequest, types.NamespacedName{Name: dynamoComponentRequest.Name, Namespace: dynamoComponentRequest.Namespace}, false) dynamoComponent, err = commonController.SyncResource(ctx, r.Client, dynamoComponent, false)
if err != nil { if err != nil {
reason = "failed_to_sync_the_DynamoComponentRequest" reason = "failed_to_sync_the_DynamoComponent"
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if !dynamoComponent.IsReady() {
logger.Info("The DynamoComponent is not ready")
reason = "dynamoComponent_is_not_ready"
message = "The DynamoComponent is not ready"
readyStatus = metav1.ConditionFalse
return ctrl.Result{}, nil
}
notReadyDeployments := []string{} notReadyDeployments := []string{}
// reconcile the dynamoComponentsDeployments // reconcile the dynamoComponentsDeployments
...@@ -185,7 +190,7 @@ func (r *DynamoGraphDeploymentReconciler) Reconcile(ctx context.Context, req ctr ...@@ -185,7 +190,7 @@ func (r *DynamoGraphDeploymentReconciler) Reconcile(ctx context.Context, req ctr
reason = "failed_to_set_the_controller_reference_for_the_DynamoComponentDeployment" reason = "failed_to_set_the_controller_reference_for_the_DynamoComponentDeployment"
return ctrl.Result{}, err return ctrl.Result{}, err
} }
dynamoComponentDeployment, err = commonController.SyncResource(ctx, r.Client, dynamoComponentDeployment, types.NamespacedName{Name: dynamoComponentDeployment.Name, Namespace: dynamoComponentDeployment.Namespace}, false) dynamoComponentDeployment, err = commonController.SyncResource(ctx, r.Client, dynamoComponentDeployment, false)
if err != nil { if err != nil {
reason = "failed_to_sync_the_DynamoComponentDeployment" reason = "failed_to_sync_the_DynamoComponentDeployment"
return ctrl.Result{}, err return ctrl.Result{}, err
...@@ -276,6 +281,13 @@ func (r *DynamoGraphDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) err ...@@ -276,6 +281,13 @@ func (r *DynamoGraphDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) err
UpdateFunc: func(de event.UpdateEvent) bool { return true }, UpdateFunc: func(de event.UpdateEvent) bool { return true },
GenericFunc: func(ge event.GenericEvent) bool { return true }, GenericFunc: func(ge event.GenericEvent) bool { return true },
})). })).
Owns(&nvidiacomv1alpha1.DynamoComponent{}, builder.WithPredicates(predicate.Funcs{
// ignore creation cause we don't want to be called again after we create the deployment
CreateFunc: func(ce event.CreateEvent) bool { return false },
DeleteFunc: func(de event.DeleteEvent) bool { return true },
UpdateFunc: func(de event.UpdateEvent) bool { return true },
GenericFunc: func(ge event.GenericEvent) bool { return true },
})).
WithEventFilter(commonController.EphemeralDeploymentEventFilter(r.Config)). WithEventFilter(commonController.EphemeralDeploymentEventFilter(r.Config)).
Complete(r) Complete(r)
} }
...@@ -41,7 +41,7 @@ type Resource interface { ...@@ -41,7 +41,7 @@ type Resource interface {
SetSpec(spec any) SetSpec(spec any)
} }
func SyncResource[T Resource](ctx context.Context, c client.Client, desired T, namespacedName types.NamespacedName, createOnly bool) (T, error) { func SyncResource[T Resource](ctx context.Context, c client.Client, desired T, createOnly bool) (T, error) {
// Retrieve the GroupVersionKind (GVK) of the desired object // Retrieve the GroupVersionKind (GVK) of the desired object
gvk, err := apiutil.GVKForObject(desired, c.Scheme()) gvk, err := apiutil.GVKForObject(desired, c.Scheme())
if err != nil { if err != nil {
...@@ -59,6 +59,10 @@ func SyncResource[T Resource](ctx context.Context, c client.Client, desired T, n ...@@ -59,6 +59,10 @@ func SyncResource[T Resource](ctx context.Context, c client.Client, desired T, n
if !ok { if !ok {
return desired, fmt.Errorf("failed to cast object to the expected type %T", desired) return desired, fmt.Errorf("failed to cast object to the expected type %T", desired)
} }
namespacedName := types.NamespacedName{
Name: desired.GetName(),
Namespace: desired.GetNamespace(),
}
// Retrieve the existing resource // Retrieve the existing resource
err = c.Get(ctx, namespacedName, current) err = c.Get(ctx, namespacedName, current)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment