Skip to content

Commit

Permalink
Add NodeSetMinorUpdateReadyCondition to NodeSet
Browse files Browse the repository at this point in the history
The NodeSetMinorUpdateReadyCondition is set if the NodeSet has been
updated with the latest version. To satisfy the check, a NodeSet must
have a completed deployment that:

- deployed a service with EDPMServiceType = 'update'
- used the latest version

Jira: https://issues.redhat.com/browse/OSPRH-8176
Signed-off-by: James Slagle <[email protected]>
  • Loading branch information
slagle committed Jul 2, 2024
1 parent 8b2b3bf commit faacaa8
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 2 deletions.
7 changes: 7 additions & 0 deletions apis/dataplane/v1beta1/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,11 @@ const (

// NodeSetServiceDeploymentErrorMessage error
NodeSetServiceDeploymentErrorMessage = "Deployment error occurred in %s service"

// NodeSetMinorUpdateReadyCondition Status=True condition indicates if the
// NodeSet minor update is finished and successful.
NodeSetMinorUpdateReadyCondition condition.Type = "NodeSetMinorUpdateReady"

// NodeSetMinorUpdateReadyMessage ready
NodeSetMinorUpdateReadyMessage = "Minor update ready for NodeSet"
)
38 changes: 36 additions & 2 deletions controllers/dataplane/openstackdataplanenodeset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ func (r *OpenStackDataPlaneNodeSetReconciler) Reconcile(ctx context.Context, req
}
}

isDeploymentReady, isDeploymentRunning, isDeploymentFailed, failedDeployment, err := checkDeployment(helper, instance)
isDeploymentReady, isDeploymentRunning, isDeploymentFailed, failedDeployment, err := checkDeployment(helper, instance, version)
if !isDeploymentFailed && err != nil {
instance.Status.Conditions.MarkFalse(
condition.DeploymentReadyCondition,
Expand Down Expand Up @@ -464,6 +464,7 @@ func (r *OpenStackDataPlaneNodeSetReconciler) Reconcile(ctx context.Context, req

func checkDeployment(helper *helper.Helper,
instance *dataplanev1.OpenStackDataPlaneNodeSet,
version *openstackv1.OpenStackVersion,
) (bool, bool, bool, string, error) {
// Get all completed deployments
var failedDeployment string
Expand Down Expand Up @@ -530,8 +531,41 @@ func checkDeployment(helper *helper.Helper,
}
instance.Status.DeployedConfigHash = deployment.Status.NodeSetHashes[instance.Name]
instance.Status.DeployedVersion = deployment.Status.DeployedVersion
}

// Get list of services by name, either from ServicesOverride or
// the NodeSet.
var services []string
if len(deployment.Spec.ServicesOverride) != 0 {
services = deployment.Spec.ServicesOverride
} else {
services = instance.Spec.Services
}

// For each service, check if EDPMServiceType is "update", and the
// deployment deployed the latest version.
for _, serviceName := range services {
service := &dataplanev1.OpenStackDataPlaneService{}
name := types.NamespacedName{
Namespace: instance.Namespace,
Name: serviceName,
}
err := helper.GetClient().Get(context.Background(), name, service)
if err != nil {
helper.GetLogger().Error(err, "Unable to retrieve OpenStackDataPlaneService %v")
return false, false, false, failedDeployment, err
}

if service.Spec.EDPMServiceType != "update" {
continue
}

if deployment.Status.DeployedVersion == version.Spec.TargetVersion {
instance.Status.Conditions.MarkTrue(
dataplanev1.NodeSetMinorUpdateReadyCondition,
dataplanev1.NodeSetMinorUpdateReadyMessage)
}
}
}
}
}

Expand Down
33 changes: 33 additions & 0 deletions tests/functional/dataplane/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,31 @@ func CreateSSHSecret(name types.NamespacedName) *corev1.Secret {
)
}

// Create OpenStackVersion
func CreateOpenStackVersion(name types.NamespacedName) *unstructured.Unstructured {
raw := DefaultOpenStackVersion(name)
return th.CreateUnstructured(raw)
}

// Struct initialization

func DefaultOpenStackVersion(name types.NamespacedName) map[string]interface{} {
return map[string]interface{}{
"apiVersion": "core.openstack.org/v1beta1",
"kind": "OpenStackVersion",
"metadata": map[string]interface{}{
"name": name.Name,
"namespace": name.Namespace,
},
"spec": map[string]interface{}{
"targetVersion": "0.0.1",
},
"status": map[string]interface{}{
"availableVersion": "0.0.1",
},
}
}

// Build OpenStackDataPlaneNodeSetSpec struct and fill it with preset values
func DefaultDataPlaneNodeSetSpec(nodeSetName string) map[string]interface{} {

Expand Down Expand Up @@ -180,6 +203,16 @@ func DefaultDataPlaneDeploymentSpec() map[string]interface{} {
}
}

func MinorUpdateDataPlaneDeploymentSpec() map[string]interface{} {

return map[string]interface{}{
"nodeSets": []string{
"edpm-compute-nodeset",
},
"servicesOverride": []string{"update"},
}
}

func DefaultNetConfigSpec() map[string]interface{} {
return map[string]interface{}{
"networks": []map[string]interface{}{{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
. "github.com/onsi/ginkgo/v2" //revive:disable:dot-imports
. "github.com/onsi/gomega" //revive:disable:dot-imports
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
ansibleeev1 "github.com/openstack-k8s-operators/openstack-ansibleee-operator/api/v1beta1"
openstackv1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1"
dataplanev1 "github.com/openstack-k8s-operators/openstack-operator/apis/dataplane/v1beta1"

//revive:disable-next-line:dot-imports
Expand Down Expand Up @@ -64,6 +66,7 @@ var _ = Describe("Dataplane NodeSet Test", func() {
var dataplaneDeploymentName types.NamespacedName
var dataplaneConfigHash string
var dataplaneGlobalServiceName types.NamespacedName
var dataplaneUpdateServiceName types.NamespacedName

defaultEdpmServiceList := []string{
"edpm_frr_image",
Expand Down Expand Up @@ -108,6 +111,10 @@ var _ = Describe("Dataplane NodeSet Test", func() {
Name: "global-service",
Namespace: namespace,
}
dataplaneUpdateServiceName = types.NamespacedName{
Name: "update",
Namespace: namespace,
}
err := os.Setenv("OPERATOR_SERVICES", "../../../config/services")
Expect(err).NotTo(HaveOccurred())
})
Expand Down Expand Up @@ -1290,4 +1297,60 @@ var _ = Describe("Dataplane NodeSet Test", func() {
}).Should(BeTrue())
})
})

When("A DataPlaneNodeSet is created with NoNodes and a MinorUpdate OpenStackDataPlaneDeployment is created", func() {
BeforeEach(func() {

updateServiceSpec := map[string]interface{}{
"playbook": "osp.edpm.update",
}
CreateDataPlaneServiceFromSpec(dataplaneUpdateServiceName, updateServiceSpec)
DeferCleanup(th.DeleteService, dataplaneUpdateServiceName)
DeferCleanup(th.DeleteInstance, CreateNetConfig(dataplaneNetConfigName, DefaultNetConfigSpec()))
DeferCleanup(th.DeleteInstance, CreateDNSMasq(dnsMasqName, DefaultDNSMasqSpec()))
DeferCleanup(th.DeleteInstance, CreateDataplaneNodeSet(dataplaneNodeSetName, DefaultDataPlaneNoNodeSetSpec(false)))
DeferCleanup(th.DeleteInstance, CreateDataplaneDeployment(dataplaneDeploymentName, MinorUpdateDataPlaneDeploymentSpec()))
openstackVersionName := types.NamespacedName{
Name: "openstackversion",
Namespace: namespace,
}
err := os.Setenv("OPENSTACK_RELEASE_VERSION", "0.0.1")
Expect(err).NotTo(HaveOccurred())
openstackv1.SetupVersionDefaults()
DeferCleanup(th.DeleteInstance, CreateOpenStackVersion(openstackVersionName))

CreateSSHSecret(dataplaneSSHSecretName)
SimulateDNSMasqComplete(dnsMasqName)
SimulateIPSetComplete(dataplaneNodeName)
SimulateDNSDataComplete(dataplaneNodeSetName)

Eventually(func(g Gomega) {
// Make an AnsibleEE name for each service
ansibleeeName := types.NamespacedName{
Name: "update-edpm-deployment-edpm-compute-nodeset",
Namespace: namespace,
}
ansibleEE := GetAnsibleee(ansibleeeName)
ansibleEE.Status.JobStatus = ansibleeev1.JobStatusSucceeded
g.Expect(th.K8sClient.Status().Update(th.Ctx, ansibleEE)).To(Succeed())
}, th.Timeout, th.Interval).Should(Succeed())

})
It("Should reach Input, Setup, and MinorUpdate Ready completion", Label("update"), func() {
var conditionList = []condition.Type{
condition.InputReadyCondition,
dataplanev1.SetupReadyCondition,
dataplanev1.NodeSetMinorUpdateReadyCondition,
}
for _, cond := range conditionList {
th.ExpectCondition(
dataplaneNodeSetName,
ConditionGetterFunc(DataplaneConditionGetter),
cond,
corev1.ConditionTrue,
)
}
})
})

})
3 changes: 3 additions & 0 deletions tests/functional/dataplane/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ var _ = BeforeSuite(func() {
err = (&dataplanev1.OpenStackDataPlaneService{}).SetupWebhookWithManager(k8sManager)
Expect(err).NotTo(HaveOccurred())

err = (&openstackv1.OpenStackVersion{}).SetupWebhookWithManager(k8sManager)
Expect(err).NotTo(HaveOccurred())

kclient, err := kubernetes.NewForConfig(cfg)
Expect(err).ToNot(HaveOccurred(), "failed to create kclient")
err = (&dataplanecontrollers.OpenStackDataPlaneNodeSetReconciler{
Expand Down

0 comments on commit faacaa8

Please sign in to comment.