diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad29125a0a48..5262c7b95cd1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -252,6 +252,71 @@ There may, at times, need to be exceptions where breaking changes are allowed in discretion of the project's maintainers, and must be carefully considered before merging. An example of an allowed breaking change might be a fix for a behavioral bug that was released in an initial minor version (such as `v0.3.0`). + +## API conventions + +In general we adhere to the [Kubernetes API conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#optional-vs-required). +We have a small set of exceptions due to the fact that we're using CRDs while the API conventions predates the introduction +of CRDs and the way our controllers only patch actual changes to the status instead of updating the entire status in every +reconciliation. + +### Optional vs. Required + +Status fields must be optional, because our controllers are patching selected fields instead of updating the entire status +in every reconciliation. + +Optional fields have the following properties: +* In general an optional field must have both an `+optional` marker and an `omitempty` JSON tag. +* If the semantic difference between nil and the zero value is important for your code, the field must also be a pointer. + * Note: This doesn't apply to map or slice types as they already have a built-in `nil` value. + * Example: When using ClusterClass, the semantic difference is important when you have a field in a template which will + have instance-specific different values in derived objects. Because in this case it's possible to set the field to `nil` + in the template and then the value can be set in derived objects without being overwritten by the cluster topology controller. + +* Exceptions: + * Fields in root objects should be kept as scaffolded by kubebuilder, e.g.: + ```golang + type Machine struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec MachineSpec `json:"spec,omitempty"` + Status MachineStatus `json:"status,omitempty"` + } + type MachineList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Machine `json:"items"` + } + ``` + * Top-level fields in `status` must always have the `+optional` annotation. If we want the field to be always visible even if it + has the zero value, it must **not** have the `omitempty` JSON tag, e.g.: + * Replica counters like `availableReplicas` in the `MachineDeployment` + * Flags expressing progress in the object lifecycle like `infrastructureReady` in `Machine` + +### CRD additionalPrinterColumns + +All our CRD objects should have the following `additionalPrinterColumns` order (if the respective field exists in the CRD): +* Namespace (added automatically) +* Name (added automatically) +* Cluster +* Other fields +* Replica-related fields +* Phase +* Age (mandatory field for all CRDs) +* Version +* Other fields for -o wide (fields with priority `1` are only shown with `-o wide` and not per default) + +Examples: +```bash +$ kubectl get kubeadmcontrolplane +NAMESPACE NAME INITIALIZED API SERVER AVAILABLE REPLICAS READY UPDATED UNAVAILABLE AGE VERSION +quick-start-d5ufye quick-start-ntysk0-control-plane true true 1 1 1 2m44s v1.22.0 +$ kubectl get machinedeployment +NAMESPACE NAME CLUSTER REPLICAS READY UPDATED UNAVAILABLE PHASE AGE VERSION +quick-start-d5ufye quick-start-ntysk0-md-0 quick-start-ntysk0 1 1 1 ScalingUp 3m28s v1.22.0 +``` + ## Google Doc Viewing Permissions To gain viewing permissions to google docs in this project, please join either the diff --git a/Makefile b/Makefile index ea61aadcc88c..ee34b2209554 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,7 @@ CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/controller-gen) GOTESTSUM := $(abspath $(TOOLS_BIN_DIR)/gotestsum) GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint) CONVERSION_GEN := $(abspath $(TOOLS_BIN_DIR)/conversion-gen) +STRUCT_VERIFIER := $(abspath $(TOOLS_BIN_DIR)/struct-verifier) ENVSUBST := $(abspath $(TOOLS_BIN_DIR)/envsubst) # clusterctl. @@ -204,6 +205,9 @@ $(GOTESTSUM): $(TOOLS_DIR)/go.mod # Build gotestsum from tools folder. $(CONVERSION_GEN): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR); go build -tags=tools -o $(BIN_DIR)/conversion-gen k8s.io/code-generator/cmd/conversion-gen +$(STRUCT_VERIFIER): $(TOOLS_DIR)/go.mod + cd $(TOOLS_DIR); go build -tags=tools -o $(BIN_DIR)/struct-verifier sigs.k8s.io/cluster-api/hack/tools/struct-verifier + $(GO_APIDIFF): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR) && go build -tags=tools -o $(GO_APIDIFF_BIN) github.com/joelanford/go-apidiff @@ -223,6 +227,7 @@ kustomize: $(KUSTOMIZE) ## Build a local copy of kustomize. setup-envtest: $(SETUP_ENVTEST) ## Build a local copy of setup-envtest. controller-gen: $(CONTROLLER_GEN) ## Build a local copy of controller-gen. conversion-gen: $(CONVERSION_GEN) ## Build a local copy of conversion-gen. +struct-verifier: $(STRUCT_VERIFIER) ## Build a local copy of struct-verifier. gotestsum: $(GOTESTSUM) ## Build a local copy of gotestsum. .PHONY: e2e-framework diff --git a/api/v1beta1/cluster_types.go b/api/v1beta1/cluster_types.go index 1279ed49bc7a..4cb7fceb0499 100644 --- a/api/v1beta1/cluster_types.go +++ b/api/v1beta1/cluster_types.go @@ -49,7 +49,7 @@ type ClusterSpec struct { // ControlPlaneEndpoint represents the endpoint used to communicate with the control plane. // +optional - ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint"` + ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint,omitempty"` // ControlPlaneRef is an optional reference to a provider-specific resource that holds // the details for provisioning the Control Plane for a Cluster. @@ -84,7 +84,7 @@ type Topology struct { // ControlPlane describes the cluster control plane. // +optional - ControlPlane ControlPlaneTopology `json:"controlPlane"` + ControlPlane ControlPlaneTopology `json:"controlPlane,omitempty"` // Workers encapsulates the different constructs that form the worker nodes // for the cluster. @@ -99,6 +99,7 @@ type ControlPlaneTopology struct { // // This field is supported if and only if the control plane provider template // referenced in the ClusterClass is Machine based. + // +optional Metadata ObjectMeta `json:"metadata,omitempty"` // Replicas is the number of control plane nodes. @@ -112,6 +113,7 @@ type ControlPlaneTopology struct { // WorkersTopology represents the different sets of worker nodes in the cluster. type WorkersTopology struct { // MachineDeployments is a list of machine deployments in the cluster. + // +optional MachineDeployments []MachineDeploymentTopology `json:"machineDeployments,omitempty"` } @@ -120,6 +122,7 @@ type WorkersTopology struct { type MachineDeploymentTopology struct { // Metadata is the metadata applied to the machines of the MachineDeployment. // At runtime this metadata is merged with the corresponding metadata from the ClusterClass. + // +optional Metadata ObjectMeta `json:"metadata,omitempty"` // Class is the name of the MachineDeploymentClass used to create the set of worker nodes. @@ -189,6 +192,7 @@ func (n *NetworkRanges) String() string { // ClusterStatus defines the observed state of Cluster. type ClusterStatus struct { // FailureDomains is a slice of failure domain objects synced from the infrastructure provider. + // +optional FailureDomains FailureDomains `json:"failureDomains,omitempty"` // FailureReason indicates that there is a fatal problem reconciling the @@ -213,7 +217,7 @@ type ClusterStatus struct { // ControlPlaneReady defines if the control plane is ready. // +optional - ControlPlaneReady bool `json:"controlPlaneReady,omitempty"` + ControlPlaneReady bool `json:"controlPlaneReady"` // Conditions defines current service state of the cluster. // +optional @@ -279,8 +283,9 @@ func (v APIEndpoint) String() string { // +kubebuilder:resource:path=clusters,shortName=cl,scope=Namespaced,categories=cluster-api // +kubebuilder:storageversion // +kubebuilder:subresource:status -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of Cluster" // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Cluster status such as Pending/Provisioning/Provisioned/Deleting/Failed" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of Cluster" +// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.topology.version",description="Kubernetes version associated with this Cluster" // Cluster is the Schema for the clusters API. type Cluster struct { @@ -427,7 +432,7 @@ func (in FailureDomains) GetIDs() []*string { type FailureDomainSpec struct { // ControlPlane determines if this failure domain is suitable for use by control plane machines. // +optional - ControlPlane bool `json:"controlPlane"` + ControlPlane bool `json:"controlPlane,omitempty"` // Attributes is a free form map of attributes an infrastructure provider might use or require. // +optional diff --git a/api/v1beta1/clusterclass_types.go b/api/v1beta1/clusterclass_types.go index 60b1b861cd4e..a7ff7aea1ee4 100644 --- a/api/v1beta1/clusterclass_types.go +++ b/api/v1beta1/clusterclass_types.go @@ -41,10 +41,12 @@ type ClusterClassSpec struct { // for the underlying provider. // The underlying provider is responsible for the implementation // of the template to an infrastructure cluster. + // +optional Infrastructure LocalObjectTemplate `json:"infrastructure,omitempty"` // ControlPlane is a reference to a local struct that holds the details // for provisioning the Control Plane for the Cluster. + // +optional ControlPlane ControlPlaneClass `json:"controlPlane,omitempty"` // Workers describes the worker nodes for the cluster. @@ -61,6 +63,7 @@ type ControlPlaneClass struct { // // This field is supported if and only if the control plane provider template // referenced is Machine based. + // +optional Metadata ObjectMeta `json:"metadata,omitempty"` // LocalObjectTemplate contains the reference to the control plane provider. @@ -80,6 +83,7 @@ type ControlPlaneClass struct { type WorkersClass struct { // MachineDeployments is a list of machine deployment classes that can be used to create // a set of worker nodes. + // +optional MachineDeployments []MachineDeploymentClass `json:"machineDeployments,omitempty"` } @@ -101,6 +105,7 @@ type MachineDeploymentClass struct { type MachineDeploymentClassTemplate struct { // Metadata is the metadata applied to the machines of the MachineDeployment. // At runtime this metadata is merged with the corresponding metadata from the topology. + // +optional Metadata ObjectMeta `json:"metadata,omitempty"` // Bootstrap contains the bootstrap template reference to be used diff --git a/api/v1beta1/condition_types.go b/api/v1beta1/condition_types.go index 40f0660acae8..7f0983e4beeb 100644 --- a/api/v1beta1/condition_types.go +++ b/api/v1beta1/condition_types.go @@ -56,11 +56,9 @@ type Condition struct { // Type of condition in CamelCase or in foo.example.com/CamelCase. // Many .condition.type values are consistent across resources like Available, but because arbitrary conditions // can be useful (see .node.status.conditions), the ability to deconflict is important. - // +required Type ConditionType `json:"type"` // Status of the condition, one of True, False, Unknown. - // +required Status corev1.ConditionStatus `json:"status"` // Severity provides an explicit classification of Reason code, so the users or machines can immediately @@ -72,8 +70,7 @@ type Condition struct { // Last time the condition transitioned from one status to another. // This should be when the underlying condition changed. If that is not known, then using the time when // the API field changed is acceptable. - // +required - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + LastTransitionTime metav1.Time `json:"lastTransitionTime"` // The reason for the condition's last transition in CamelCase. // The specific API may choose whether or not this field is considered a guaranteed API. diff --git a/api/v1beta1/machine_types.go b/api/v1beta1/machine_types.go index da5b06d31498..b2bb9e6b73c5 100644 --- a/api/v1beta1/machine_types.go +++ b/api/v1beta1/machine_types.go @@ -237,11 +237,11 @@ type Bootstrap struct { // +kubebuilder:subresource:status // +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".spec.clusterName",description="Cluster" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of Machine" +// +kubebuilder:printcolumn:name="NodeName",type="string",JSONPath=".status.nodeRef.name",description="Node name associated with this machine" // +kubebuilder:printcolumn:name="ProviderID",type="string",JSONPath=".spec.providerID",description="Provider ID" // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Machine status such as Terminating/Pending/Running/Failed etc" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of Machine" // +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.version",description="Kubernetes version associated with this Machine" -// +kubebuilder:printcolumn:name="NodeName",type="string",JSONPath=".status.nodeRef.name",description="Node name associated with this machine",priority=1 // Machine is the Schema for the machines API. type Machine struct { diff --git a/api/v1beta1/machinedeployment_types.go b/api/v1beta1/machinedeployment_types.go index f43d2d4df5fc..96e4121b108f 100644 --- a/api/v1beta1/machinedeployment_types.go +++ b/api/v1beta1/machinedeployment_types.go @@ -104,6 +104,7 @@ type MachineDeploymentSpec struct { // process failed deployments and a condition with a ProgressDeadlineExceeded // reason will be surfaced in the deployment status. Note that progress will // not be estimated during the time a deployment is paused. Defaults to 600s. + // +optional ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty"` } @@ -190,21 +191,36 @@ type MachineDeploymentStatus struct { // Total number of non-terminated machines targeted by this deployment // (their labels match the selector). // +optional - Replicas int32 `json:"replicas,omitempty"` + Replicas int32 `json:"replicas"` // Total number of non-terminated machines targeted by this deployment // that have the desired template spec. // +optional - UpdatedReplicas int32 `json:"updatedReplicas,omitempty"` + UpdatedReplicas int32 `json:"updatedReplicas"` + + // Note: shows up in status + // +optional + TestReplicas int32 `json:"testReplicas"` + + // +optional + TestReplicasOmitEmpty int32 `json:"testReplicasOmitEmpty,omitempty"` + + // Note: shows up in status + // +optional + TestReplicasPointer *int32 `json:"testReplicasPointer"` + + // Note: shows up in status + // +optional + TestReplicasPointerOmitEmpty *int32 `json:"testReplicasPointerOmitEmpty,omitempty"` // Total number of ready machines targeted by this deployment. // +optional - ReadyReplicas int32 `json:"readyReplicas,omitempty"` + ReadyReplicas int32 `json:"readyReplicas"` // Total number of available machines (ready for at least minReadySeconds) // targeted by this deployment. // +optional - AvailableReplicas int32 `json:"availableReplicas,omitempty"` + AvailableReplicas int32 `json:"availableReplicas"` // Total number of unavailable machines targeted by this deployment. // This is the total number of machines that are still required for @@ -212,7 +228,7 @@ type MachineDeploymentStatus struct { // be machines that are running but not yet available or machines // that still have not been created. // +optional - UnavailableReplicas int32 `json:"unavailableReplicas,omitempty"` + UnavailableReplicas int32 `json:"unavailableReplicas"` // Phase represents the current phase of a MachineDeployment (ScalingUp, ScalingDown, Running, Failed, or Unknown). // +optional @@ -271,12 +287,13 @@ func (md *MachineDeploymentStatus) GetTypedPhase() MachineDeploymentPhase { // +kubebuilder:subresource:status // +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector // +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".spec.clusterName",description="Cluster" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachineDeployment" -// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="MachineDeployment status such as ScalingUp/ScalingDown/Running/Failed/Unknown" // +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".status.replicas",description="Total number of non-terminated machines targeted by this MachineDeployment" // +kubebuilder:printcolumn:name="Ready",type="integer",JSONPath=".status.readyReplicas",description="Total number of ready machines targeted by this MachineDeployment" // +kubebuilder:printcolumn:name="Updated",type=integer,JSONPath=".status.updatedReplicas",description="Total number of non-terminated machines targeted by this deployment that have the desired template spec" // +kubebuilder:printcolumn:name="Unavailable",type=integer,JSONPath=".status.unavailableReplicas",description="Total number of unavailable machines targeted by this MachineDeployment" +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="MachineDeployment status such as ScalingUp/ScalingDown/Running/Failed/Unknown" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachineDeployment" +// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.template.spec.version",description="Kubernetes version associated with this MachineDeployment" // MachineDeployment is the Schema for the machinedeployments API. type MachineDeployment struct { diff --git a/api/v1beta1/machinedeployment_types_test.go b/api/v1beta1/machinedeployment_types_test.go new file mode 100644 index 000000000000..a0a85f05ee0a --- /dev/null +++ b/api/v1beta1/machinedeployment_types_test.go @@ -0,0 +1,73 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "fmt" + "testing" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var testScheme = runtime.NewScheme() + +func init() { + _ = clientgoscheme.AddToScheme(testScheme) + _ = apiextensionsv1.AddToScheme(testScheme) + _ = AddToScheme(testScheme) +} + +func TestList(t *testing.T) { + cfg := ctrl.GetConfigOrDie() + + c, err := client.New(cfg, client.Options{ + Scheme: testScheme, + }) + if err != nil { + panic(err) + } + + ctx := context.Background() + + list := &MachineDeploymentList{} + if err := c.List(ctx, list); err != nil { + panic(err) + } + + md := &MachineDeployment{} + if err := c.Get(ctx, client.ObjectKey{Namespace: "quick-start-hr8mgd", Name: "quick-start-bcd1q5-md-0"}, md); err != nil { + panic(err) + } + + md.Status.TestReplicasPointer = nil + md.Status.TestReplicasPointerOmitEmpty = nil + if err := c.Status().Update(ctx, md); err != nil { + panic(err) + } + + mdfinal := &MachineDeployment{} + if err := c.Get(ctx, client.ObjectKey{Namespace: "quick-start-hr8mgd", Name: "quick-start-bcd1q5-md-0"}, mdfinal); err != nil { + panic(err) + } + + fmt.Println(list) +} diff --git a/api/v1beta1/machinehealthcheck_types.go b/api/v1beta1/machinehealthcheck_types.go index e730cd55072f..a8d120351861 100644 --- a/api/v1beta1/machinehealthcheck_types.go +++ b/api/v1beta1/machinehealthcheck_types.go @@ -98,16 +98,19 @@ type UnhealthyCondition struct { type MachineHealthCheckStatus struct { // total number of machines counted by this machine health check // +kubebuilder:validation:Minimum=0 - ExpectedMachines int32 `json:"expectedMachines,omitempty"` + // +optional + ExpectedMachines int32 `json:"expectedMachines"` // total number of healthy machines counted by this machine health check // +kubebuilder:validation:Minimum=0 - CurrentHealthy int32 `json:"currentHealthy,omitempty"` + // +optional + CurrentHealthy int32 `json:"currentHealthy"` // RemediationsAllowed is the number of further remediations allowed by this machine health check before // maxUnhealthy short circuiting will be applied // +kubebuilder:validation:Minimum=0 - RemediationsAllowed int32 `json:"remediationsAllowed,omitempty"` + // +optional + RemediationsAllowed int32 `json:"remediationsAllowed"` // ObservedGeneration is the latest generation observed by the controller. // +optional @@ -129,10 +132,10 @@ type MachineHealthCheckStatus struct { // +kubebuilder:storageversion // +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".spec.clusterName",description="Cluster" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachineHealthCheck" -// +kubebuilder:printcolumn:name="MaxUnhealthy",type="string",JSONPath=".spec.maxUnhealthy",description="Maximum number of unhealthy machines allowed" // +kubebuilder:printcolumn:name="ExpectedMachines",type="integer",JSONPath=".status.expectedMachines",description="Number of machines currently monitored" +// +kubebuilder:printcolumn:name="MaxUnhealthy",type="string",JSONPath=".spec.maxUnhealthy",description="Maximum number of unhealthy machines allowed" // +kubebuilder:printcolumn:name="CurrentHealthy",type="integer",JSONPath=".status.currentHealthy",description="Current observed healthy machines" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachineHealthCheck" // MachineHealthCheck is the Schema for the machinehealthchecks API. type MachineHealthCheck struct { diff --git a/api/v1beta1/machineset_types.go b/api/v1beta1/machineset_types.go index e0b610bd0c72..6dea5a275c46 100644 --- a/api/v1beta1/machineset_types.go +++ b/api/v1beta1/machineset_types.go @@ -53,6 +53,7 @@ type MachineSetSpec struct { // DeletePolicy defines the policy used to identify nodes to delete when downscaling. // Defaults to "Random". Valid values are "Random, "Newest", "Oldest" // +kubebuilder:validation:Enum=Random;Newest;Oldest + // +optional DeletePolicy string `json:"deletePolicy,omitempty"` // Selector is a label query over machines that should match the replica count. @@ -123,19 +124,19 @@ type MachineSetStatus struct { // Replicas is the most recently observed number of replicas. // +optional - Replicas int32 `json:"replicas,omitempty"` + Replicas int32 `json:"replicas"` // The number of replicas that have labels matching the labels of the machine template of the MachineSet. // +optional - FullyLabeledReplicas int32 `json:"fullyLabeledReplicas,omitempty"` + FullyLabeledReplicas int32 `json:"fullyLabeledReplicas"` // The number of ready replicas for this MachineSet. A machine is considered ready when the node has been created and is "Ready". // +optional - ReadyReplicas int32 `json:"readyReplicas,omitempty"` + ReadyReplicas int32 `json:"readyReplicas"` // The number of available replicas (ready for at least minReadySeconds) for this MachineSet. // +optional - AvailableReplicas int32 `json:"availableReplicas,omitempty"` + AvailableReplicas int32 `json:"availableReplicas"` // ObservedGeneration reflects the generation of the most recently observed MachineSet. // +optional @@ -199,10 +200,11 @@ func (m *MachineSet) Validate() field.ErrorList { // +kubebuilder:subresource:status // +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector // +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".spec.clusterName",description="Cluster" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachineSet" // +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".status.replicas",description="Total number of non-terminated machines targeted by this machineset" -// +kubebuilder:printcolumn:name="Available",type="integer",JSONPath=".status.availableReplicas",description="Total number of available machines (ready for at least minReadySeconds)" // +kubebuilder:printcolumn:name="Ready",type="integer",JSONPath=".status.readyReplicas",description="Total number of ready machines targeted by this machineset." +// +kubebuilder:printcolumn:name="Available",type="integer",JSONPath=".status.availableReplicas",description="Total number of available machines (ready for at least minReadySeconds)" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachineSet" +// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.template.spec.version",description="Kubernetes version associated with this MachineSet" // MachineSet is the Schema for the machinesets API. type MachineSet struct { diff --git a/bootstrap/kubeadm/api/v1beta1/kubeadm_types.go b/bootstrap/kubeadm/api/v1beta1/kubeadm_types.go index b0a92b063b2f..2c7514761dea 100644 --- a/bootstrap/kubeadm/api/v1beta1/kubeadm_types.go +++ b/bootstrap/kubeadm/api/v1beta1/kubeadm_types.go @@ -218,6 +218,7 @@ type NodeRegistrationOptions struct { // Taints specifies the taints the Node API object should be registered with. If this field is unset, i.e. nil, in the `kubeadm init` process // it will be defaulted to []v1.Taint{'node-role.kubernetes.io/master=""'}. If you don't want to taint your control-plane node, set this field to an // empty slice, i.e. `taints: {}` in the YAML file. This field is solely used for Node registration. + // +optional Taints []corev1.Taint `json:"taints,omitempty"` // KubeletExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file diff --git a/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types.go b/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types.go index d86af563d875..7a252155be9d 100644 --- a/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types.go +++ b/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types.go @@ -99,7 +99,8 @@ type KubeadmConfigSpec struct { // KubeadmConfigStatus defines the observed state of KubeadmConfig. type KubeadmConfigStatus struct { // Ready indicates the BootstrapData field is ready to be consumed - Ready bool `json:"ready,omitempty"` + // +optional + Ready bool `json:"ready"` // DataSecretName is the name of the secret that stores the bootstrap data script. // +optional @@ -279,8 +280,11 @@ type NTP struct { // DiskSetup defines input for generated disk_setup and fs_setup in cloud-init. type DiskSetup struct { // Partitions specifies the list of the partitions to setup. + // +optional Partitions []Partition `json:"partitions,omitempty"` + // Filesystems specifies the list of file systems to setup. + // +optional Filesystems []Filesystem `json:"filesystems,omitempty"` } diff --git a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml index 5f3bb0de50cf..73ef0f0bb4ca 100644 --- a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml +++ b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml @@ -2945,6 +2945,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/bootstrap/kubeadm/config/default/manager_image_patch.yaml b/bootstrap/kubeadm/config/default/manager_image_patch.yaml index b30b919bdbfd..7e792790c1be 100644 --- a/bootstrap/kubeadm/config/default/manager_image_patch.yaml +++ b/bootstrap/kubeadm/config/default/manager_image_patch.yaml @@ -7,5 +7,5 @@ spec: template: spec: containers: - - image: gcr.io/k8s-staging-cluster-api/kubeadm-bootstrap-controller:master + - image: gcr.io/k8s-staging-cluster-api/kubeadm-bootstrap-controller-amd64:dev name: manager diff --git a/bootstrap/kubeadm/config/default/manager_pull_policy.yaml b/bootstrap/kubeadm/config/default/manager_pull_policy.yaml index 74a0879c604a..cd7ae12c01ea 100644 --- a/bootstrap/kubeadm/config/default/manager_pull_policy.yaml +++ b/bootstrap/kubeadm/config/default/manager_pull_policy.yaml @@ -8,4 +8,4 @@ spec: spec: containers: - name: manager - imagePullPolicy: Always + imagePullPolicy: IfNotPresent diff --git a/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml b/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml index 0ff326e3de70..e3c209e2ce6e 100644 --- a/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml +++ b/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml @@ -486,6 +486,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/config/crd/bases/cluster.x-k8s.io_clusters.yaml b/config/crd/bases/cluster.x-k8s.io_clusters.yaml index 53f5c34cb494..0ecb60a52052 100644 --- a/config/crd/bases/cluster.x-k8s.io_clusters.yaml +++ b/config/crd/bases/cluster.x-k8s.io_clusters.yaml @@ -660,13 +660,17 @@ spec: subresources: status: {} - additionalPrinterColumns: + - description: Cluster status such as Pending/Provisioning/Provisioned/Deleting/Failed + jsonPath: .status.phase + name: Phase + type: string - description: Time duration since creation of Cluster jsonPath: .metadata.creationTimestamp name: Age type: date - - description: Cluster status such as Pending/Provisioning/Provisioned/Deleting/Failed - jsonPath: .status.phase - name: Phase + - description: Kubernetes version associated with this Cluster + jsonPath: .spec.topology.version + name: Version type: string name: v1beta1 schema: @@ -988,6 +992,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml b/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml index 1a84edafb2b3..364e00c987e8 100644 --- a/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml +++ b/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml @@ -967,14 +967,6 @@ spec: jsonPath: .spec.clusterName name: Cluster type: string - - description: Time duration since creation of MachineDeployment - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: MachineDeployment status such as ScalingUp/ScalingDown/Running/Failed/Unknown - jsonPath: .status.phase - name: Phase - type: string - description: Total number of non-terminated machines targeted by this MachineDeployment jsonPath: .status.replicas name: Replicas @@ -992,6 +984,18 @@ spec: jsonPath: .status.unavailableReplicas name: Unavailable type: integer + - description: MachineDeployment status such as ScalingUp/ScalingDown/Running/Failed/Unknown + jsonPath: .status.phase + name: Phase + type: string + - description: Time duration since creation of MachineDeployment + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Kubernetes version associated with this MachineDeployment + jsonPath: .spec.template.spec.version + name: Version + type: string name: v1beta1 schema: openAPIV3Schema: @@ -1370,6 +1374,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object @@ -1397,6 +1402,21 @@ spec: be in the same format as the query-param syntax. More info about label selectors: http://kubernetes.io/docs/user-guide/labels#label-selectors' type: string + testReplicas: + description: 'Note: shows up in status' + format: int32 + type: integer + testReplicasOmitEmpty: + format: int32 + type: integer + testReplicasPointer: + description: 'Note: shows up in status' + format: int32 + type: integer + testReplicasPointerOmitEmpty: + description: 'Note: shows up in status' + format: int32 + type: integer unavailableReplicas: description: Total number of unavailable machines targeted by this deployment. This is the total number of machines that are still diff --git a/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml b/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml index 7078dbd073b8..006121d1fdd3 100644 --- a/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml +++ b/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml @@ -545,22 +545,22 @@ spec: jsonPath: .spec.clusterName name: Cluster type: string - - description: Time duration since creation of MachineHealthCheck - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: Maximum number of unhealthy machines allowed - jsonPath: .spec.maxUnhealthy - name: MaxUnhealthy - type: string - description: Number of machines currently monitored jsonPath: .status.expectedMachines name: ExpectedMachines type: integer + - description: Maximum number of unhealthy machines allowed + jsonPath: .spec.maxUnhealthy + name: MaxUnhealthy + type: string - description: Current observed healthy machines jsonPath: .status.currentHealthy name: CurrentHealthy type: integer + - description: Time duration since creation of MachineHealthCheck + jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1beta1 schema: openAPIV3Schema: @@ -769,6 +769,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/config/crd/bases/cluster.x-k8s.io_machinepools.yaml b/config/crd/bases/cluster.x-k8s.io_machinepools.yaml index 857f6cd8af59..4536d621eaf3 100644 --- a/config/crd/bases/cluster.x-k8s.io_machinepools.yaml +++ b/config/crd/bases/cluster.x-k8s.io_machinepools.yaml @@ -966,10 +966,6 @@ spec: statusReplicasPath: .status.replicas status: {} - additionalPrinterColumns: - - description: Time duration since creation of MachinePool - jsonPath: .metadata.creationTimestamp - name: Age - type: date - description: MachinePool replicas count jsonPath: .status.replicas name: Replicas @@ -979,6 +975,10 @@ spec: jsonPath: .status.phase name: Phase type: string + - description: Time duration since creation of MachinePool + jsonPath: .metadata.creationTimestamp + name: Age + type: date - description: Kubernetes version associated with this MachinePool jsonPath: .spec.template.spec.version name: Version @@ -1252,6 +1252,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/config/crd/bases/cluster.x-k8s.io_machines.yaml b/config/crd/bases/cluster.x-k8s.io_machines.yaml index 3dd919f605d5..3842a0d6991c 100644 --- a/config/crd/bases/cluster.x-k8s.io_machines.yaml +++ b/config/crd/bases/cluster.x-k8s.io_machines.yaml @@ -751,10 +751,10 @@ spec: jsonPath: .spec.clusterName name: Cluster type: string - - description: Time duration since creation of Machine - jsonPath: .metadata.creationTimestamp - name: Age - type: date + - description: Node name associated with this machine + jsonPath: .status.nodeRef.name + name: NodeName + type: string - description: Provider ID jsonPath: .spec.providerID name: ProviderID @@ -763,15 +763,14 @@ spec: jsonPath: .status.phase name: Phase type: string + - description: Time duration since creation of Machine + jsonPath: .metadata.creationTimestamp + name: Age + type: date - description: Kubernetes version associated with this Machine jsonPath: .spec.version name: Version type: string - - description: Node name associated with this machine - jsonPath: .status.nodeRef.name - name: NodeName - priority: 1 - type: string name: v1beta1 schema: openAPIV3Schema: @@ -984,6 +983,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/config/crd/bases/cluster.x-k8s.io_machinesets.yaml b/config/crd/bases/cluster.x-k8s.io_machinesets.yaml index bcce46d0873d..f4246bf776bf 100644 --- a/config/crd/bases/cluster.x-k8s.io_machinesets.yaml +++ b/config/crd/bases/cluster.x-k8s.io_machinesets.yaml @@ -847,22 +847,26 @@ spec: jsonPath: .spec.clusterName name: Cluster type: string - - description: Time duration since creation of MachineSet - jsonPath: .metadata.creationTimestamp - name: Age - type: date - description: Total number of non-terminated machines targeted by this machineset jsonPath: .status.replicas name: Replicas type: integer - - description: Total number of available machines (ready for at least minReadySeconds) - jsonPath: .status.availableReplicas - name: Available - type: integer - description: Total number of ready machines targeted by this machineset. jsonPath: .status.readyReplicas name: Ready type: integer + - description: Total number of available machines (ready for at least minReadySeconds) + jsonPath: .status.availableReplicas + name: Available + type: integer + - description: Time duration since creation of MachineSet + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Kubernetes version associated with this MachineSet + jsonPath: .spec.template.spec.version + name: Version + type: string name: v1beta1 schema: openAPIV3Schema: @@ -1175,6 +1179,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/config/default/manager_image_patch.yaml b/config/default/manager_image_patch.yaml index 472f75963741..acaecdad5257 100644 --- a/config/default/manager_image_patch.yaml +++ b/config/default/manager_image_patch.yaml @@ -7,5 +7,5 @@ spec: template: spec: containers: - - image: gcr.io/k8s-staging-cluster-api/cluster-api-controller:master + - image: gcr.io/k8s-staging-cluster-api/cluster-api-controller-amd64:dev name: manager diff --git a/config/default/manager_pull_policy.yaml b/config/default/manager_pull_policy.yaml index 74a0879c604a..cd7ae12c01ea 100644 --- a/config/default/manager_pull_policy.yaml +++ b/config/default/manager_pull_policy.yaml @@ -8,4 +8,4 @@ spec: spec: containers: - name: manager - imagePullPolicy: Always + imagePullPolicy: IfNotPresent diff --git a/controllers/external/util.go b/controllers/external/util.go index ff2ad581b493..0f29f90239f4 100644 --- a/controllers/external/util.go +++ b/controllers/external/util.go @@ -68,19 +68,15 @@ func Delete(ctx context.Context, c client.Client, ref *corev1.ObjectReference) e // CloneTemplateInput is the input to CloneTemplate. type CloneTemplateInput struct { // Client is the controller runtime client. - // +required Client client.Client // TemplateRef is a reference to the template that needs to be cloned. - // +required TemplateRef *corev1.ObjectReference // Namespace is the Kubernetes namespace the cloned object should be created into. - // +required Namespace string // ClusterName is the cluster this object is linked to. - // +required ClusterName string // OwnerRef is an optional OwnerReference to attach to the cloned object. @@ -127,19 +123,15 @@ func CloneTemplate(ctx context.Context, in *CloneTemplateInput) (*corev1.ObjectR // GenerateTemplateInput is the input needed to generate a new template. type GenerateTemplateInput struct { // Template is the TemplateRef turned into an unstructured. - // +required Template *unstructured.Unstructured // TemplateRef is a reference to the template that needs to be cloned. - // +required TemplateRef *corev1.ObjectReference // Namespace is the Kubernetes namespace the cloned object should be created into. - // +required Namespace string // ClusterName is the cluster this object is linked to. - // +required ClusterName string // OwnerRef is an optional OwnerReference to attach to the cloned object. diff --git a/controllers/machinedeployment_sync.go b/controllers/machinedeployment_sync.go index 032a6f4f49bc..eaeb24eb893b 100644 --- a/controllers/machinedeployment_sync.go +++ b/controllers/machinedeployment_sync.go @@ -396,16 +396,21 @@ func calculateStatus(allMSs []*clusterv1.MachineSet, newMS *clusterv1.MachineSet // Calculate the label selector. We check the error in the MD reconcile function, ignore here. selector, _ := metav1.LabelSelectorAsSelector(&deployment.Spec.Selector) + i := mdutil.GetActualReplicaCountForMachineSets(allMSs) status := clusterv1.MachineDeploymentStatus{ // TODO: Ensure that if we start retrying status updates, we won't pick up a new Generation value. - ObservedGeneration: deployment.Generation, - Selector: selector.String(), - Replicas: mdutil.GetActualReplicaCountForMachineSets(allMSs), - UpdatedReplicas: mdutil.GetActualReplicaCountForMachineSets([]*clusterv1.MachineSet{newMS}), - ReadyReplicas: mdutil.GetReadyReplicaCountForMachineSets(allMSs), - AvailableReplicas: availableReplicas, - UnavailableReplicas: unavailableReplicas, - Conditions: deployment.Status.Conditions, + ObservedGeneration: deployment.Generation, + Selector: selector.String(), + Replicas: mdutil.GetActualReplicaCountForMachineSets(allMSs), + TestReplicas: i, + TestReplicasOmitEmpty: i, + TestReplicasPointer: &i, + TestReplicasPointerOmitEmpty: &i, + UpdatedReplicas: mdutil.GetActualReplicaCountForMachineSets([]*clusterv1.MachineSet{newMS}), + ReadyReplicas: mdutil.GetReadyReplicaCountForMachineSets(allMSs), + AvailableReplicas: availableReplicas, + UnavailableReplicas: unavailableReplicas, + Conditions: deployment.Status.Conditions, } if *deployment.Spec.Replicas == status.ReadyReplicas { diff --git a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_types.go b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_types.go index aae95bd761a0..4a889c1c0cda 100644 --- a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_types.go +++ b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_types.go @@ -142,7 +142,7 @@ type KubeadmControlPlaneStatus struct { // Total number of non-terminated machines targeted by this control plane // (their labels match the selector). // +optional - Replicas int32 `json:"replicas,omitempty"` + Replicas int32 `json:"replicas"` // Version represents the minimum Kubernetes version for the control plane machines // in the cluster. @@ -152,11 +152,11 @@ type KubeadmControlPlaneStatus struct { // Total number of non-terminated machines targeted by this control plane // that have the desired template spec. // +optional - UpdatedReplicas int32 `json:"updatedReplicas,omitempty"` + UpdatedReplicas int32 `json:"updatedReplicas"` // Total number of fully running and ready control plane machines. // +optional - ReadyReplicas int32 `json:"readyReplicas,omitempty"` + ReadyReplicas int32 `json:"readyReplicas"` // Total number of unavailable machines targeted by this control plane. // This is the total number of machines that are still required for @@ -164,7 +164,7 @@ type KubeadmControlPlaneStatus struct { // be machines that are running but not yet ready or machines // that still have not been created. // +optional - UnavailableReplicas int32 `json:"unavailableReplicas,omitempty"` + UnavailableReplicas int32 `json:"unavailableReplicas"` // Initialized denotes whether or not the control plane has the // uploaded kubeadm-config configmap. @@ -201,14 +201,14 @@ type KubeadmControlPlaneStatus struct { // +kubebuilder:storageversion // +kubebuilder:subresource:status // +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of KubeadmControlPlane" // +kubebuilder:printcolumn:name="Initialized",type=boolean,JSONPath=".status.initialized",description="This denotes whether or not the control plane has the uploaded kubeadm-config configmap" // +kubebuilder:printcolumn:name="API Server Available",type=boolean,JSONPath=".status.ready",description="KubeadmControlPlane API Server is ready to receive requests" -// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=".spec.version",description="Kubernetes version associated with this control plane" // +kubebuilder:printcolumn:name="Replicas",type=integer,JSONPath=".status.replicas",description="Total number of non-terminated machines targeted by this control plane" // +kubebuilder:printcolumn:name="Ready",type=integer,JSONPath=".status.readyReplicas",description="Total number of fully running and ready control plane machines" // +kubebuilder:printcolumn:name="Updated",type=integer,JSONPath=".status.updatedReplicas",description="Total number of non-terminated machines targeted by this control plane that have the desired template spec" // +kubebuilder:printcolumn:name="Unavailable",type=integer,JSONPath=".status.unavailableReplicas",description="Total number of unavailable machines targeted by this control plane" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of KubeadmControlPlane" +// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=".spec.version",description="Kubernetes version associated with this control plane" // KubeadmControlPlane is the Schema for the KubeadmControlPlane API. type KubeadmControlPlane struct { diff --git a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml index b3b027288e7f..1c74f3e67542 100644 --- a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml +++ b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml @@ -2403,10 +2403,6 @@ spec: statusReplicasPath: .status.replicas status: {} - additionalPrinterColumns: - - description: Time duration since creation of KubeadmControlPlane - jsonPath: .metadata.creationTimestamp - name: Age - type: date - description: This denotes whether or not the control plane has the uploaded kubeadm-config configmap jsonPath: .status.initialized @@ -2416,10 +2412,6 @@ spec: jsonPath: .status.ready name: API Server Available type: boolean - - description: Kubernetes version associated with this control plane - jsonPath: .spec.version - name: Version - type: string - description: Total number of non-terminated machines targeted by this control plane jsonPath: .status.replicas @@ -2438,6 +2430,14 @@ spec: jsonPath: .status.unavailableReplicas name: Unavailable type: integer + - description: Time duration since creation of KubeadmControlPlane + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Kubernetes version associated with this control plane + jsonPath: .spec.version + name: Version + type: string name: v1beta1 schema: openAPIV3Schema: @@ -3542,6 +3542,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/controlplane/kubeadm/config/default/manager_image_patch.yaml b/controlplane/kubeadm/config/default/manager_image_patch.yaml index 46ae15ec140c..ee85cda73fa8 100644 --- a/controlplane/kubeadm/config/default/manager_image_patch.yaml +++ b/controlplane/kubeadm/config/default/manager_image_patch.yaml @@ -7,5 +7,5 @@ spec: template: spec: containers: - - image: gcr.io/k8s-staging-cluster-api/kubeadm-control-plane-controller:master + - image: gcr.io/k8s-staging-cluster-api/kubeadm-control-plane-controller-amd64:dev name: manager diff --git a/controlplane/kubeadm/config/default/manager_pull_policy.yaml b/controlplane/kubeadm/config/default/manager_pull_policy.yaml index 74a0879c604a..cd7ae12c01ea 100644 --- a/controlplane/kubeadm/config/default/manager_pull_policy.yaml +++ b/controlplane/kubeadm/config/default/manager_pull_policy.yaml @@ -8,4 +8,4 @@ spec: spec: containers: - name: manager - imagePullPolicy: Always + imagePullPolicy: IfNotPresent diff --git a/docs/proposals/20200506-conditions.md b/docs/proposals/20200506-conditions.md index 00f4733e68d8..eb98e201cdf6 100644 --- a/docs/proposals/20200506-conditions.md +++ b/docs/proposals/20200506-conditions.md @@ -179,11 +179,9 @@ const ( // Condition defines an extension to status (i.e. an observation) of a Cluster API resource. type Condition struct { // Type of condition. - // +required Type ConditionType `json:"type" description:"type of status condition"` // Status of the condition, one of True, False, Unknown. - // +required Status corev1.ConditionStatus `json:"status"` // Severity with which to treat failures of this type of condition. @@ -192,8 +190,7 @@ type Condition struct { Severity ConditionSeverity `json:"severity,omitempty"` // LastTransitionTime is the last time the condition transitioned from one status to another. - // +required - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + LastTransitionTime metav1.Time `json:"lastTransitionTime"` // The reason for the condition's last transition. // Reasons should be CamelCase. diff --git a/exp/addons/api/v1beta1/clusterresourceset_types.go b/exp/addons/api/v1beta1/clusterresourceset_types.go index 55465fb8b0f0..579034caa332 100644 --- a/exp/addons/api/v1beta1/clusterresourceset_types.go +++ b/exp/addons/api/v1beta1/clusterresourceset_types.go @@ -41,6 +41,7 @@ type ClusterResourceSetSpec struct { ClusterSelector metav1.LabelSelector `json:"clusterSelector"` // Resources is a list of Secrets/ConfigMaps where each contains 1 or more resources to be applied to remote clusters. + // +optional Resources []ResourceRef `json:"resources,omitempty"` // Strategy is the strategy to be used during applying resources. Defaults to ApplyOnce. This field is immutable. diff --git a/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go b/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go index f5832deca7e1..14f15991bf6b 100644 --- a/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go +++ b/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go @@ -31,6 +31,7 @@ type ResourceBinding struct { // Hash is the hash of a resource's data. This can be used to decide if a resource is changed. // For "ApplyOnce" ClusterResourceSet.spec.strategy, this is no-op as that strategy does not act on change. + // +optional Hash string `json:"hash,omitempty"` // LastAppliedTime identifies when this resource was last applied to the cluster. @@ -49,6 +50,7 @@ type ResourceSetBinding struct { ClusterResourceSetName string `json:"clusterResourceSetName"` // Resources is a list of resources that the ClusterResourceSet has. + // +optional Resources []ResourceBinding `json:"resources,omitempty"` } @@ -118,6 +120,7 @@ type ClusterResourceSetBinding struct { // ClusterResourceSetBindingSpec defines the desired state of ClusterResourceSetBinding. type ClusterResourceSetBindingSpec struct { // Bindings is a list of ClusterResourceSets and their resources. + // +optional Bindings []*ResourceSetBinding `json:"bindings,omitempty"` } diff --git a/exp/api/v1beta1/machinepool_types.go b/exp/api/v1beta1/machinepool_types.go index 3d20efd5ba0b..327ce1ed4695 100644 --- a/exp/api/v1beta1/machinepool_types.go +++ b/exp/api/v1beta1/machinepool_types.go @@ -38,6 +38,7 @@ type MachinePoolSpec struct { // Number of desired machines. Defaults to 1. // This is a pointer to distinguish between explicit zero and not specified. + // +optional Replicas *int32 `json:"replicas,omitempty"` // Template describes the machines that will be created. @@ -56,6 +57,7 @@ type MachinePoolSpec struct { ProviderIDList []string `json:"providerIDList,omitempty"` // FailureDomains is the list of failure domains this MachinePool should be attached to. + // +optional FailureDomains []string `json:"failureDomains,omitempty"` } @@ -202,9 +204,9 @@ func (m *MachinePoolStatus) GetTypedPhase() MachinePoolPhase { // +kubebuilder:subresource:status // +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas // +kubebuilder:storageversion -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachinePool" // +kubebuilder:printcolumn:name="Replicas",type="string",JSONPath=".status.replicas",description="MachinePool replicas count" // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="MachinePool status such as Terminating/Pending/Provisioning/Running/Failed etc" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of MachinePool" // +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.template.spec.version",description="Kubernetes version associated with this MachinePool" // +k8s:conversion-gen=false diff --git a/hack/tools/go.mod b/hack/tools/go.mod index c38f631a2816..28f0908e3e5e 100644 --- a/hack/tools/go.mod +++ b/hack/tools/go.mod @@ -5,13 +5,17 @@ go 1.16 require ( github.com/blang/semver v3.5.1+incompatible github.com/drone/envsubst/v2 v2.0.0-20210615175204-7bf45dbf5372 + github.com/hashicorp/go-multierror v1.0.0 github.com/joelanford/go-apidiff v0.1.0 + github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/ginkgo v1.16.4 + github.com/pkg/errors v0.9.1 github.com/sergi/go-diff v1.2.0 // indirect golang.org/x/exp v0.0.0-20210625193404-fa9d1d177d71 // indirect golang.org/x/tools v0.1.5 gotest.tools/gotestsum v1.6.4 k8s.io/code-generator v0.22.2 + k8s.io/klog/v2 v2.9.0 sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20210827150604-1730628f118b sigs.k8s.io/controller-tools v0.7.0 sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20210702145813-742983631190 diff --git a/hack/tools/go.sum b/hack/tools/go.sum index f387d23523e7..2e8c30c413e5 100644 --- a/hack/tools/go.sum +++ b/hack/tools/go.sum @@ -309,10 +309,12 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -392,6 +394,8 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -434,6 +438,8 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/hack/tools/struct-verifier/main.go b/hack/tools/struct-verifier/main.go new file mode 100644 index 000000000000..c8d7cd15da51 --- /dev/null +++ b/hack/tools/struct-verifier/main.go @@ -0,0 +1,169 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "bytes" + "fmt" + "go/printer" + "os" + "strings" + + "github.com/olekukonko/tablewriter" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-tools/pkg/loader" + "sigs.k8s.io/controller-tools/pkg/markers" +) + +var ( + optionalMarker = markers.Must(markers.MakeDefinition("optional", markers.DescribesField, struct{}{})) + omitEmpty = "omitempty" +) + +type fieldInfo struct { + field markers.FieldInfo + structName string + typeName string + omitEmpty bool + optional bool + pointer bool + pointerType bool +} + +func main() { + // Define the marker collector. + col := &markers.Collector{ + Registry: &markers.Registry{}, + } + // Register the markers. + if err := col.Registry.Register(optionalMarker); err != nil { + klog.Fatal(err) + } + + // Load all packages. + packages, err := loader.LoadRoots("./...") + if err != nil { + klog.Fatal(err) + } + + var fieldInfos []fieldInfo + + for i := range packages { + root := packages[i] + + if !strings.HasSuffix(root.PkgPath, "/api/v1beta1") { + // We're only interested in api/v1beta1 folders for now, exclude everything + // else that's not an API package. + continue + } + + // Populate type information and loop through every type. + root.NeedTypesInfo() + if err := markers.EachType(col, root, func(info *markers.TypeInfo) { + // Check if the type is registered with storage version. + for _, field := range info.Fields { + var foundOptionalMarker bool + var foundOmitEmpty bool + var foundPointer bool + var foundPointerType bool + + if m := field.Markers.Get(optionalMarker.Name); m != nil { + foundOptionalMarker = true + } + if strings.Contains(string(field.Tag), omitEmpty) { + foundOmitEmpty = true + } + + var typeNameBuf bytes.Buffer + if err := printer.Fprint(&typeNameBuf, root.Fset, field.RawField.Type); err != nil { + klog.Errorf(err.Error()) + } + typeName := typeNameBuf.String() + + if strings.HasPrefix(typeName, "*") { + foundPointer = true + } + + if strings.HasPrefix(typeName, "*") || + strings.HasPrefix(typeName, "map") || + strings.HasPrefix(typeName, "[]") { + foundPointerType = true + } + + // Let's ignore Spec and Status + if field.Name == "Spec" || field.Name == "Status" { + continue + } + + // Let's ignore top-level ListMeta and ObjectMeta + if field.Name == "" && (typeName == "metav1.ListMeta" || typeName == "metav1.ObjectMeta") { + continue + } + + fieldInfos = append(fieldInfos, fieldInfo{ + field: field, + structName: info.Name, + typeName: typeName, + omitEmpty: foundOmitEmpty, + optional: foundOptionalMarker, + pointer: foundPointer, + pointerType: foundPointerType, + }) + + } + }); err != nil { + klog.Fatal(err) + } + } + + // Overview contains all fields which have one of optional, omitEmpty and pointer, but not all + printTable("### Overview", fieldInfos, func(field fieldInfo) bool { + return (field.optional || field.omitEmpty || field.pointer) && + (!(field.optional && field.omitEmpty && field.pointer)) + }) + + printTable("### Optional without omitempty", fieldInfos, func(field fieldInfo) bool { return field.optional && !field.omitEmpty }) + + printTable("### Omitempty without optional", fieldInfos, func(field fieldInfo) bool { return !field.optional && field.omitEmpty }) +} + +func printTable(title string, fieldInfos []fieldInfo, pred func(field fieldInfo) bool) { + fmt.Printf("%s\n\n", title) + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Name", "Type", "Optional", "Omitempty", "Pointer", "PointerType"}) + table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) + table.SetCenterSeparator("|") + for _, field := range fieldInfos { + if !pred(field) { + continue + } + table.Append(calculateRow(field)) + } + table.Render() + fmt.Println() +} + +func calculateRow(field fieldInfo) []string { + return []string{fmt.Sprintf("%s.%s", field.structName, field.field.Name), field.typeName, boolToX(field.optional), boolToX(field.omitEmpty), boolToX(field.pointer), boolToX(field.pointerType)} +} + +func boolToX(b bool) string { + if b { + return "x" + } + return "" +} diff --git a/test/infrastructure/docker/api/v1beta1/dockercluster_types.go b/test/infrastructure/docker/api/v1beta1/dockercluster_types.go index eb3e79ab04f3..0be17c72dcc2 100644 --- a/test/infrastructure/docker/api/v1beta1/dockercluster_types.go +++ b/test/infrastructure/docker/api/v1beta1/dockercluster_types.go @@ -71,10 +71,12 @@ type ImageMeta struct { // DockerClusterStatus defines the observed state of DockerCluster. type DockerClusterStatus struct { // Ready denotes that the docker cluster (infrastructure) is ready. + // +optional Ready bool `json:"ready"` // FailureDomains don't mean much in CAPD since it's all local, but we can see how the rest of cluster API // will use this if we populate it. + // +optional FailureDomains clusterv1.FailureDomains `json:"failureDomains,omitempty"` // Conditions defines current service state of the DockerCluster. diff --git a/test/infrastructure/docker/api/v1beta1/dockermachine_types.go b/test/infrastructure/docker/api/v1beta1/dockermachine_types.go index 17dd0f7a339d..55e822f593a4 100644 --- a/test/infrastructure/docker/api/v1beta1/dockermachine_types.go +++ b/test/infrastructure/docker/api/v1beta1/dockermachine_types.go @@ -79,7 +79,7 @@ type DockerMachineStatus struct { // LoadBalancerConfigured denotes that the machine has been // added to the load balancer // +optional - LoadBalancerConfigured bool `json:"loadBalancerConfigured,omitempty"` + LoadBalancerConfigured bool `json:"loadBalancerConfigured"` // Addresses contains the associated addresses for the docker machine. // +optional diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml index 1f216829e5fc..88bd7607cdda 100644 --- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml +++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml @@ -431,6 +431,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object @@ -460,8 +461,6 @@ spec: description: Ready denotes that the docker cluster (infrastructure) is ready. type: boolean - required: - - ready type: object type: object served: true diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml index 761bf9829c85..15c278283fd9 100644 --- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml +++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml @@ -492,6 +492,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml index d3af52862a73..7dd6cf688061 100644 --- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml +++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml @@ -433,6 +433,7 @@ spec: important. type: string required: + - lastTransitionTime - status - type type: object diff --git a/test/infrastructure/docker/config/default/manager_image_patch.yaml b/test/infrastructure/docker/config/default/manager_image_patch.yaml index 2b0a3fe80d8e..078b7b393ae4 100644 --- a/test/infrastructure/docker/config/default/manager_image_patch.yaml +++ b/test/infrastructure/docker/config/default/manager_image_patch.yaml @@ -8,5 +8,5 @@ spec: spec: containers: # Change the value of image field below to your controller image URL - - image: gcr.io/k8s-staging-cluster-api/capd-manager:master + - image: gcr.io/k8s-staging-cluster-api/capd-manager-amd64:dev name: manager diff --git a/test/infrastructure/docker/config/default/manager_pull_policy.yaml b/test/infrastructure/docker/config/default/manager_pull_policy.yaml index 74a0879c604a..cd7ae12c01ea 100644 --- a/test/infrastructure/docker/config/default/manager_pull_policy.yaml +++ b/test/infrastructure/docker/config/default/manager_pull_policy.yaml @@ -8,4 +8,4 @@ spec: spec: containers: - name: manager - imagePullPolicy: Always + imagePullPolicy: IfNotPresent