github.com/nmstate/kubernetes-nmstate@v0.82.0/test/e2e/upgrade/upgrade_test.go (about)

     1  /*
     2  Copyright The Kubernetes NMState Authors.
     3  
     4  
     5  Licensed under the Apache License, Version 2.0 (the "License");
     6  you may not use this file except in compliance with the License.
     7  You may obtain a copy of the License at
     8  
     9      http://www.apache.org/licenses/LICENSE-2.0
    10  
    11  Unless required by applicable law or agreed to in writing, software
    12  distributed under the License is distributed on an "AS IS" BASIS,
    13  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  See the License for the specific language governing permissions and
    15  limitations under the License.
    16  */
    17  
    18  package upgrade
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"os"
    24  	"path"
    25  	"time"
    26  
    27  	. "github.com/onsi/ginkgo/v2"
    28  	. "github.com/onsi/gomega"
    29  
    30  	corev1 "k8s.io/api/core/v1"
    31  
    32  	nmstate "github.com/nmstate/kubernetes-nmstate/api/shared"
    33  	nmstatev1 "github.com/nmstate/kubernetes-nmstate/api/v1"
    34  	"github.com/nmstate/kubernetes-nmstate/test/cmd"
    35  	"github.com/nmstate/kubernetes-nmstate/test/doc"
    36  	"github.com/nmstate/kubernetes-nmstate/test/e2e/operator"
    37  	testenv "github.com/nmstate/kubernetes-nmstate/test/env"
    38  )
    39  
    40  var _ = Describe("Upgrade", func() {
    41  	interfaceAbsent := func(iface string) nmstate.State {
    42  		return nmstate.NewState(fmt.Sprintf(`interfaces:
    43  - name: %s
    44    state: absent
    45  `, iface))
    46  	}
    47  
    48  	previousTagExamplesPath := "test/e2e/upgrade/examples"
    49  	currentExamplesPath := "docs/examples"
    50  
    51  	fileExists := func(path string) (bool, error) {
    52  		_, err := os.Stat(path)
    53  		exists := false
    54  
    55  		if err == nil {
    56  			exists = true
    57  		} else if os.IsNotExist(err) {
    58  			err = nil
    59  		}
    60  		return exists, err
    61  	}
    62  
    63  	kubectlAndCheck := func(command ...string) {
    64  		out, err := cmd.Kubectl(command...)
    65  		Expect(err).ShouldNot(HaveOccurred(), out)
    66  	}
    67  
    68  	createUpgradeCasePolicy := func(example doc.ExampleSpec) {
    69  		examplePath := path.Join(previousTagExamplesPath, example.FileName)
    70  		exists, err := fileExists(examplePath)
    71  		Expect(err).NotTo(HaveOccurred())
    72  		if !exists {
    73  			examplePath = path.Join(currentExamplesPath, example.FileName)
    74  		}
    75  
    76  		By(fmt.Sprintf("Creating policy %s", example.PolicyName))
    77  		kubectlAndCheck("apply", "-f", examplePath)
    78  		By("Waiting for policy to be available")
    79  		kubectlAndCheck("wait", "nncp", example.PolicyName, "--for", "condition=Available", "--timeout", "3m")
    80  	}
    81  
    82  	createUpgradeCaseCleanupPolicy := func(example doc.ExampleSpec) {
    83  		if example.CleanupState != nil {
    84  			setDesiredStateWithPolicyEventually(example.PolicyName, *example.CleanupState)
    85  		}
    86  		if len(example.IfaceNames) > 0 {
    87  			for _, ifaceName := range example.IfaceNames {
    88  				setDesiredStateWithPolicyEventually(
    89  					example.PolicyName,
    90  					interfaceAbsent(ifaceName),
    91  				)
    92  			}
    93  		}
    94  
    95  		kubectlAndCheck("wait", "nncp", example.PolicyName, "--for", "condition=Available", "--timeout", "3m")
    96  	}
    97  
    98  	BeforeEach(func() {
    99  		operator.UninstallOperator(latestOperator)
   100  		operator.InstallOperator(previousReleaseOperator)
   101  		operator.EventuallyOperandIsReady(previousReleaseOperator)
   102  	})
   103  
   104  	Context("With examples", func() {
   105  		for _, e := range doc.ExampleSpecs() {
   106  			example := e
   107  
   108  			Context(example.Name, func() {
   109  				It("should succeed applying the policy", func() {
   110  					//TODO: remove when no longer required
   111  					for _, policyToSkip := range []string{"vlan", "linux-bridge-vlan", "dns", "enable-lldp-ethernets-up"} {
   112  						if policyToSkip == example.PolicyName {
   113  							Skip("Skipping due to malformed example manifest")
   114  						}
   115  					}
   116  					createUpgradeCasePolicy(example)
   117  				})
   118  				AfterEach(func() {
   119  					policiesLastHeartbeatTimestamps := map[string]time.Time{}
   120  
   121  					nncps := nmstatev1.NodeNetworkConfigurationPolicyList{}
   122  					err := testenv.Client.List(context.TODO(), &nncps)
   123  					Expect(err).ToNot(HaveOccurred())
   124  
   125  					By("Collecting LastHeartbeatTime timestamps of present policies")
   126  					for _, nncp := range nncps.Items {
   127  						availableCondition := nncp.Status.Conditions.Find(nmstate.NodeNetworkConfigurationPolicyConditionAvailable)
   128  						Expect(availableCondition).ToNot(BeNil())
   129  						policiesLastHeartbeatTimestamps[nncp.Name] = availableCondition.LastHeartbeatTime.Time
   130  					}
   131  
   132  					By("Applying new nmstate operator")
   133  					operator.UninstallOperator(previousReleaseOperator)
   134  					operator.InstallOperator(latestOperator)
   135  					operator.EventuallyOperandIsReady(latestOperator)
   136  
   137  					By("Waiting for all policies to be re-reconciled")
   138  					allPoliciesReReconciled := func() error {
   139  						nncps = nmstatev1.NodeNetworkConfigurationPolicyList{}
   140  						err = testenv.Client.List(context.TODO(), &nncps)
   141  						if err != nil {
   142  							return err
   143  						}
   144  						for _, nncp := range nncps.Items {
   145  							availableCondition := nncp.Status.Conditions.Find(nmstate.NodeNetworkConfigurationPolicyConditionAvailable)
   146  							if availableCondition.Status != corev1.ConditionTrue {
   147  								return fmt.Errorf("policy %s is not Available", nncp.Name)
   148  							}
   149  							if !availableCondition.LastHeartbeatTime.Time.After(policiesLastHeartbeatTimestamps[nncp.Name]) {
   150  								return fmt.Errorf("policy  %s hasn't re-reconciled yet", nncp.Name)
   151  							}
   152  						}
   153  						return nil
   154  					}
   155  					Eventually(func() error {
   156  						return allPoliciesReReconciled()
   157  					}, ReadTimeout, ReadInterval).Should(Succeed())
   158  
   159  					By("Wait for policy to be Available again")
   160  					kubectlAndCheck("wait", "nncp", example.PolicyName, "--for", "condition=Available", "--timeout", "3m")
   161  
   162  					By("Apply cleanup policy configuration")
   163  					createUpgradeCaseCleanupPolicy(example)
   164  
   165  					By("Delete policy")
   166  					deletePolicy(example.PolicyName)
   167  				})
   168  			})
   169  		}
   170  	})
   171  })