From 3c0df319d755118216c61087282b11abbb2e886e25905f203211cd49147690f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Fri, 3 Apr 2026 01:04:40 +0800 Subject: [PATCH] Draft for OSUpgrade Spec --- README.md | 52 ++++++-- clitools/makefile | 18 +-- .../pkg/apis/monok8s/v1alpha1/monoksconfig.go | 77 ++++++++++++ .../pkg/apis/monok8s/v1alpha1/osupgrade.go | 109 +++++++++++++++++ clitools/pkg/apis/monok8s/v1alpha1/types.go | 114 ------------------ clitools/pkg/node/agent.go | 4 +- clitools/pkg/templates/templates.go | 18 +-- 7 files changed, 250 insertions(+), 142 deletions(-) create mode 100644 clitools/pkg/apis/monok8s/v1alpha1/monoksconfig.go create mode 100644 clitools/pkg/apis/monok8s/v1alpha1/osupgrade.go diff --git a/README.md b/README.md index 86b3d31..fc4351c 100644 --- a/README.md +++ b/README.md @@ -90,29 +90,61 @@ We use a CRD with an agent to handle this. Our versions follows upstream's. kubectl apply -f upgrade.yaml ```yaml -apiVersion: k8s.mono.si/v1alpha1 +apiVersion: monok8s.io/v1alpha1 kind: OSUpgrade metadata: - name: "my-ugrade" + name: "my-ugrade-2" spec: - version: "v1.35.1" # Or just "latest" + version: "v1.35.3" imageURL: "https://updates.example.com/monok8s-1.2.3.img.zst" checksum: "sha256:..." + nodeSelector: {} +status: + phase: Pending + resolvedVersion: "v1.35.3" + observedGeneration: 1 + summary: + targetedNodes: 0 + pendingNodes: 0 + runningNodes: 0 + succeededNodes: 0 + failedNodes: 0 ``` kubectl get osugrades ``` -NAME TARGET STATUS AGE -my-upgrade-1 latest pending 1m -my-upgrade-2 v1.35.3 accepted 1m # latest gets realized into a version number -their-upgrade v1.33.2 succeeded 1m +NAME TARGET STATUS AGE +my-upgrade-2 v1.35.3 accepted 1m # latest gets realized into a version number +my-downgrade-1 v1.33.2 rejected 1m # Downgrade not supported ``` kubectl get osupgradeprogress ``` -NODE SOURCE STATUS -my-node my-upgrade-2 active -their-node my-upgrade-2 completed +NAME NODE SOURCE CURRENT TARGET STATUS +osupgrade-abc123f node-1 my-upgrade-2 v1.34.1 v1.35.3 downloading +osupgrade-cde456g node-2 my-upgrade-2 v1.35.3 v1.35.3 completed +``` + +```yaml +apiVersion: monok8s.io/v1alpha1 +kind: OSUpgradeProgress +metadata: + name: "osupgrade-abc123f" +spec: + sourceRef: + name: my-upgrade-2 + nodeName: node-1 +status: + currentVersion: "v1.34.1" + targetVersion: "v1.35.3" + phase: Downloading + startedAt: null + completedAt: null + lastUpdatedAt: null + retryCount: 0 + inactivePartition: "B" + failureReason: "" + message: "" ``` ## NOTES diff --git a/clitools/makefile b/clitools/makefile index 98e1bc0..4564640 100644 --- a/clitools/makefile +++ b/clitools/makefile @@ -12,14 +12,16 @@ BUILDINFO_FILE := pkg/buildinfo/buildinfo_gen.go # Never cache this .buildinfo: - echo 'package buildinfo' > $(BUILDINFO_FILE) - echo 'const (' >> $(BUILDINFO_FILE) - echo ' Version = "$(VERSION)"' >> $(BUILDINFO_FILE) - echo ' KubeVersion = "$(KUBE_VERSION)"' >> $(BUILDINFO_FILE) - echo ' GitRevision = "$(GIT_REV)"' >> $(BUILDINFO_FILE) - echo ' Timestamp = "$(shell TZ=UTC date +%Y%m%d.%H%M%S)"' >> $(BUILDINFO_FILE) - echo ')' >> $(BUILDINFO_FILE) - echo '' + @printf '%s\n' \ + 'package buildinfo' \ + '' \ + 'const (' \ + ' Version = "$(VERSION)"' \ + ' KubeVersion = "$(KUBE_VERSION)"' \ + ' GitRevision = "$(GIT_REV)"' \ + ' Timestamp = "'$$(TZ=UTC date +%Y%m%d.%H%M%S)'"' \ + ')' \ + > $(BUILDINFO_FILE) build: .buildinfo mkdir -p $(BIN_DIR) diff --git a/clitools/pkg/apis/monok8s/v1alpha1/monoksconfig.go b/clitools/pkg/apis/monok8s/v1alpha1/monoksconfig.go new file mode 100644 index 0000000..758af8e --- /dev/null +++ b/clitools/pkg/apis/monok8s/v1alpha1/monoksconfig.go @@ -0,0 +1,77 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type MonoKSConfig struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + Spec MonoKSConfigSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Status *MonoKSConfigStatus `json:"status,omitempty" yaml:"status,omitempty"` +} + +type MonoKSConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []MonoKSConfig `json:"items"` +} + +type MonoKSConfigSpec struct { + KubernetesVersion string `json:"kubernetesVersion,omitempty" yaml:"kubernetesVersion,omitempty"` + NodeName string `json:"nodeName,omitempty" yaml:"nodeName,omitempty"` + ClusterName string `json:"clusterName,omitempty" yaml:"clusterName,omitempty"` + ClusterDomain string `json:"clusterDomain,omitempty" yaml:"clusterDomain,omitempty"` + ClusterRole string `json:"clusterRole,omitempty" yaml:"clusterRole,omitempty"` + InitControlPlane bool `json:"initControlPlane,omitempty" yaml:"initControlPlane,omitempty"` + EnableControlAgent bool `json:"enableControlAgent,omitempty" yaml:"enableControlAgent,omitempty"` + PodSubnet string `json:"podSubnet,omitempty" yaml:"podSubnet,omitempty"` + ServiceSubnet string `json:"serviceSubnet,omitempty" yaml:"serviceSubnet,omitempty"` + APIServerAdvertiseAddress string `json:"apiServerAdvertiseAddress,omitempty" yaml:"apiServerAdvertiseAddress,omitempty"` + APIServerEndpoint string `json:"apiServerEndpoint,omitempty" yaml:"apiServerEndpoint,omitempty"` + ContainerRuntimeEndpoint string `json:"containerRuntimeEndpoint,omitempty" yaml:"containerRuntimeEndpoint,omitempty"` + BootstrapToken string `json:"bootstrapToken,omitempty" yaml:"bootstrapToken,omitempty"` + DiscoveryTokenCACertHash string `json:"discoveryTokenCACertHash,omitempty" yaml:"discoveryTokenCACertHash,omitempty"` + ControlPlaneCertKey string `json:"controlPlaneCertKey,omitempty" yaml:"controlPlaneCertKey,omitempty"` + CNIPlugin string `json:"cniPlugin,omitempty" yaml:"cniPlugin,omitempty"` + AllowSchedulingOnControlPlane bool `json:"allowSchedulingOnControlPlane,omitempty" yaml:"allowSchedulingOnControlPlane,omitempty"` + SkipImageCheck bool `json:"skipImageCheck,omitempty" yaml:"skipImageCheck,omitempty"` + KubeProxyNodePortAddresses []string `json:"kubeProxyNodePortAddresses,omitempty" yaml:"kubeProxyNodePortAddresses,omitempty"` + SubjectAltNames []string `json:"subjectAltNames,omitempty" yaml:"subjectAltNames,omitempty"` + NodeLabels map[string]string `json:"nodeLabels,omitempty" yaml:"nodeLabels,omitempty"` + NodeAnnotations map[string]string `json:"nodeAnnotations,omitempty" yaml:"nodeAnnotations,omitempty"` + Network NetworkSpec `json:"network,omitempty" yaml:"network,omitempty"` +} + +type NetworkSpec struct { + Hostname string `json:"hostname,omitempty" yaml:"hostname,omitempty"` + ManagementIface string `json:"managementIface,omitempty" yaml:"managementIface,omitempty"` + ManagementCIDR string `json:"managementCIDR,omitempty" yaml:"managementCIDR,omitempty"` + ManagementGW string `json:"managementGateway,omitempty" yaml:"managementGateway,omitempty"` + DNSNameservers []string `json:"dnsNameservers,omitempty" yaml:"dnsNameservers,omitempty"` + DNSSearchDomains []string `json:"dnsSearchDomains,omitempty" yaml:"dnsSearchDomains,omitempty"` +} + +type MonoKSConfigStatus struct { + Phase string `json:"phase,omitempty"` + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` + AppliedSteps []string `json:"appliedSteps,omitempty"` +} + +func (in *MonoKSConfig) DeepCopyObject() runtime.Object { + if in == nil { + return nil + } + out := *in + return &out +} + +func (in *MonoKSConfigList) DeepCopyObject() runtime.Object { + if in == nil { + return nil + } + out := *in + return &out +} diff --git a/clitools/pkg/apis/monok8s/v1alpha1/osupgrade.go b/clitools/pkg/apis/monok8s/v1alpha1/osupgrade.go new file mode 100644 index 0000000..bd9329b --- /dev/null +++ b/clitools/pkg/apis/monok8s/v1alpha1/osupgrade.go @@ -0,0 +1,109 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type OSUpgrade struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + Spec OSUpgradeSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Status *OSUpgradeStatus `json:"status,omitempty" yaml:"status,omitempty"` +} + +type OSUpgradeList struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + Items []OSUpgrade `json:"items" yaml:"items"` +} + +type OSUpgradeSpec struct { + Version string `json:"version,omitempty" yaml:"version,omitempty"` + ImageURL string `json:"imageURL,omitempty" yaml:"imageURL,omitempty"` + Checksum string `json:"checksum,omitempty" yaml:"checksum,omitempty"` + NodeSelector *metav1.LabelSelector `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"` +} + +type OSUpgradeStatus struct { + Phase string `json:"phase,omitempty" yaml:"phase,omitempty"` + ResolvedVersion string `json:"resolvedVersion,omitempty" yaml:"resolvedVersion,omitempty"` + ObservedGeneration int64 `json:"observedGeneration,omitempty" yaml:"observedGeneration,omitempty"` + Summary OSUpgradeSummary `json:"summary,omitempty" yaml:"summary,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty" yaml:"conditions,omitempty"` +} + +type OSUpgradeSummary struct { + TargetedNodes int32 `json:"targetedNodes,omitempty" yaml:"targetedNodes,omitempty"` + PendingNodes int32 `json:"pendingNodes,omitempty" yaml:"pendingNodes,omitempty"` + RunningNodes int32 `json:"runningNodes,omitempty" yaml:"runningNodes,omitempty"` + SucceededNodes int32 `json:"succeededNodes,omitempty" yaml:"succeededNodes,omitempty"` + FailedNodes int32 `json:"failedNodes,omitempty" yaml:"failedNodes,omitempty"` +} + +type OSUpgradeProgress struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + Spec OSUpgradeProgressSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Status *OSUpgradeProgressStatus `json:"status,omitempty" yaml:"status,omitempty"` +} + +type OSUpgradeProgressList struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + Items []OSUpgradeProgress `json:"items" yaml:"items"` +} + +type OSUpgradeProgressSpec struct { + SourceRef OSUpgradeSourceRef `json:"sourceRef,omitempty" yaml:"sourceRef,omitempty"` + NodeName string `json:"nodeName,omitempty" yaml:"nodeName,omitempty"` +} + +type OSUpgradeSourceRef struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` +} + +type OSUpgradeProgressStatus struct { + CurrentVersion string `json:"currentVersion,omitempty" yaml:"currentVersion,omitempty"` + TargetVersion string `json:"targetVersion,omitempty" yaml:"targetVersion,omitempty"` + Phase string `json:"phase,omitempty" yaml:"phase,omitempty"` + StartedAt *metav1.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"` + CompletedAt *metav1.Time `json:"completedAt,omitempty" yaml:"completedAt,omitempty"` + LastUpdatedAt *metav1.Time `json:"lastUpdatedAt,omitempty" yaml:"lastUpdatedAt,omitempty"` + RetryCount int32 `json:"retryCount,omitempty" yaml:"retryCount,omitempty"` + InactivePartition string `json:"inactivePartition,omitempty" yaml:"inactivePartition,omitempty"` + FailureReason string `json:"failureReason,omitempty" yaml:"failureReason,omitempty"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` +} + +func (in *OSUpgrade) DeepCopyObject() runtime.Object { + if in == nil { + return nil + } + out := *in + return &out +} + +func (in *OSUpgradeList) DeepCopyObject() runtime.Object { + if in == nil { + return nil + } + out := *in + return &out +} + +func (in *OSUpgradeProgress) DeepCopyObject() runtime.Object { + if in == nil { + return nil + } + out := *in + return &out +} + +func (in *OSUpgradeProgressList) DeepCopyObject() runtime.Object { + if in == nil { + return nil + } + out := *in + return &out +} diff --git a/clitools/pkg/apis/monok8s/v1alpha1/types.go b/clitools/pkg/apis/monok8s/v1alpha1/types.go index 9ee1a69..ec2e469 100644 --- a/clitools/pkg/apis/monok8s/v1alpha1/types.go +++ b/clitools/pkg/apis/monok8s/v1alpha1/types.go @@ -17,88 +17,6 @@ var ( AddToScheme = SchemeBuilder.AddToScheme ) -type MonoKSConfig struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` - Spec MonoKSConfigSpec `json:"spec,omitempty" yaml:"spec,omitempty"` - Status *MonoKSConfigStatus `json:"status,omitempty" yaml:"status,omitempty"` -} - -type MonoKSConfigList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []MonoKSConfig `json:"items"` -} - -type MonoKSConfigSpec struct { - KubernetesVersion string `json:"kubernetesVersion,omitempty" yaml:"kubernetesVersion,omitempty"` - NodeName string `json:"nodeName,omitempty" yaml:"nodeName,omitempty"` - ClusterName string `json:"clusterName,omitempty" yaml:"clusterName,omitempty"` - ClusterDomain string `json:"clusterDomain,omitempty" yaml:"clusterDomain,omitempty"` - ClusterRole string `json:"clusterRole,omitempty" yaml:"clusterRole,omitempty"` - InitControlPlane bool `json:"initControlPlane,omitempty" yaml:"initControlPlane,omitempty"` - EnableControlAgent bool `json:"enableControlAgent,omitempty" yaml:"enableControlAgent,omitempty"` - PodSubnet string `json:"podSubnet,omitempty" yaml:"podSubnet,omitempty"` - ServiceSubnet string `json:"serviceSubnet,omitempty" yaml:"serviceSubnet,omitempty"` - APIServerAdvertiseAddress string `json:"apiServerAdvertiseAddress,omitempty" yaml:"apiServerAdvertiseAddress,omitempty"` - APIServerEndpoint string `json:"apiServerEndpoint,omitempty" yaml:"apiServerEndpoint,omitempty"` - ContainerRuntimeEndpoint string `json:"containerRuntimeEndpoint,omitempty" yaml:"containerRuntimeEndpoint,omitempty"` - BootstrapToken string `json:"bootstrapToken,omitempty" yaml:"bootstrapToken,omitempty"` - DiscoveryTokenCACertHash string `json:"discoveryTokenCACertHash,omitempty" yaml:"discoveryTokenCACertHash,omitempty"` - ControlPlaneCertKey string `json:"controlPlaneCertKey,omitempty" yaml:"controlPlaneCertKey,omitempty"` - CNIPlugin string `json:"cniPlugin,omitempty" yaml:"cniPlugin,omitempty"` - AllowSchedulingOnControlPlane bool `json:"allowSchedulingOnControlPlane,omitempty" yaml:"allowSchedulingOnControlPlane,omitempty"` - SkipImageCheck bool `json:"skipImageCheck,omitempty" yaml:"skipImageCheck,omitempty"` - KubeProxyNodePortAddresses []string `json:"kubeProxyNodePortAddresses,omitempty" yaml:"kubeProxyNodePortAddresses,omitempty"` - SubjectAltNames []string `json:"subjectAltNames,omitempty" yaml:"subjectAltNames,omitempty"` - NodeLabels map[string]string `json:"nodeLabels,omitempty" yaml:"nodeLabels,omitempty"` - NodeAnnotations map[string]string `json:"nodeAnnotations,omitempty" yaml:"nodeAnnotations,omitempty"` - Network NetworkSpec `json:"network,omitempty" yaml:"network,omitempty"` -} - -type NetworkSpec struct { - Hostname string `json:"hostname,omitempty" yaml:"hostname,omitempty"` - ManagementIface string `json:"managementIface,omitempty" yaml:"managementIface,omitempty"` - ManagementCIDR string `json:"managementCIDR,omitempty" yaml:"managementCIDR,omitempty"` - ManagementGW string `json:"managementGateway,omitempty" yaml:"managementGateway,omitempty"` - DNSNameservers []string `json:"dnsNameservers,omitempty" yaml:"dnsNameservers,omitempty"` - DNSSearchDomains []string `json:"dnsSearchDomains,omitempty" yaml:"dnsSearchDomains,omitempty"` -} - -type MonoKSConfigStatus struct { - Phase string `json:"phase,omitempty"` - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - Conditions []metav1.Condition `json:"conditions,omitempty"` - AppliedSteps []string `json:"appliedSteps,omitempty"` -} - -type OSUpgrade struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` - Spec OSUpgradeSpec `json:"spec,omitempty" yaml:"spec,omitempty"` - Status *OSUpgradeStatus `json:"status,omitempty" yaml:"status,omitempty"` -} - -type OSUpgradeList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []OSUpgrade `json:"items"` -} - -type OSUpgradeSpec struct { - Version string `json:"version,omitempty" yaml:"version,omitempty"` - ImageURL string `json:"imageURL,omitempty" yaml:"imageURL,omitempty"` - TargetPartition string `json:"targetPartition,omitempty" yaml:"targetPartition,omitempty"` - NodeSelector []string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"` - Force bool `json:"force,omitempty" yaml:"force,omitempty"` -} - -type OSUpgradeStatus struct { - Phase string `json:"phase,omitempty"` - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &MonoKSConfig{}, @@ -109,35 +27,3 @@ func addKnownTypes(scheme *runtime.Scheme) error { metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } - -func (in *MonoKSConfig) DeepCopyObject() runtime.Object { - if in == nil { - return nil - } - out := *in - return &out -} - -func (in *MonoKSConfigList) DeepCopyObject() runtime.Object { - if in == nil { - return nil - } - out := *in - return &out -} - -func (in *OSUpgrade) DeepCopyObject() runtime.Object { - if in == nil { - return nil - } - out := *in - return &out -} - -func (in *OSUpgradeList) DeepCopyObject() runtime.Object { - if in == nil { - return nil - } - out := *in - return &out -} diff --git a/clitools/pkg/node/agent.go b/clitools/pkg/node/agent.go index c875281..93a1b94 100644 --- a/clitools/pkg/node/agent.go +++ b/clitools/pkg/node/agent.go @@ -16,11 +16,11 @@ import ( "undecided.project/monok8s/pkg/crds" "undecided.project/monok8s/pkg/kube" + templates "undecided.project/monok8s/pkg/templates" ) const ( controlAgentName = "control-agent" - controlAgentDefaultNamespace = "kube-system" controlAgentNodeSelectorKey = "monok8s.io/control-agent" controlAgentNodeSelectorValue = "true" controlAgentImage = "localhost/monok8s/control-agent:dev" @@ -84,7 +84,7 @@ func ApplyControlAgentDaemonSetResources(ctx context.Context, n *NodeContext) er namespace := strings.TrimSpace(n.Config.Namespace) if namespace == "" { - namespace = controlAgentDefaultNamespace + namespace = templates.DefaultNamespace } clients, err := kube.NewClientsFromKubeconfig(kubeconfig) diff --git a/clitools/pkg/templates/templates.go b/clitools/pkg/templates/templates.go index 934a4da..b5ef898 100644 --- a/clitools/pkg/templates/templates.go +++ b/clitools/pkg/templates/templates.go @@ -7,6 +7,8 @@ import ( types "undecided.project/monok8s/pkg/apis/monok8s/v1alpha1" ) +const DefaultNamespace = "kube-system" + func DefaultMonoKSConfig(v TemplateValues) types.MonoKSConfig { return types.MonoKSConfig{ TypeMeta: metav1.TypeMeta{ @@ -15,7 +17,7 @@ func DefaultMonoKSConfig(v TemplateValues) types.MonoKSConfig { }, ObjectMeta: metav1.ObjectMeta{ Name: "example", - Namespace: "kube-system", + Namespace: DefaultNamespace, }, Spec: types.MonoKSConfigSpec{ KubernetesVersion: v.KubernetesVersion, @@ -71,16 +73,16 @@ func DefaultOSUpgrade(v TemplateValues) types.OSUpgrade { }, ObjectMeta: metav1.ObjectMeta{ Name: "example", - Namespace: "kube-system", + Namespace: DefaultNamespace, }, Spec: types.OSUpgradeSpec{ - Version: "v0.0.1", - ImageURL: "https://example.invalid/images/monok8s-v0.0.1.img.zst", - TargetPartition: "B", - NodeSelector: []string{ - firstNonEmpty(v.NodeName, v.Hostname), + Version: v.KubernetesVersion, + ImageURL: "https://example.invalid/images/monok8s-v0.0.1.img.zst", + NodeSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "kubernetes.io/hostname": firstNonEmpty(v.NodeName, v.Hostname), + }, }, - Force: false, }, } }