@@ -12,6 +12,7 @@ import (
1212 o "github.com/onsi/gomega"
1313 exutil "github.com/openshift/machine-config-operator/test/extended-priv/util"
1414 logger "github.com/openshift/machine-config-operator/test/extended-priv/util/logext"
15+ "github.com/tidwall/gjson"
1516 "k8s.io/apimachinery/pkg/util/wait"
1617 e2e "k8s.io/kubernetes/test/e2e/framework"
1718)
@@ -848,3 +849,197 @@ func DebugDegradedStatus(mcp *MachineConfigPool) {
848849 logger .Infof ("Last %d lines of MCC:\n %s" , maxMCCLines , GetLastNLines (mccLogs , maxMCCLines ))
849850 logger .Infof ("END DEBUG" )
850851}
852+
853+ // DeleteCustomMCP deletes a custom MCP and removes its labels from all nodes
854+ func DeleteCustomMCP (oc * exutil.CLI , name string ) error {
855+ mcp := NewMachineConfigPool (oc , name )
856+ if ! mcp .Exists () {
857+ logger .Infof ("MCP %s does not exist. No need to remove it" , mcp .GetName ())
858+ return nil
859+ }
860+
861+ exutil .By (fmt .Sprintf ("Removing custom MCP %s" , name ))
862+
863+ nodes , err := mcp .GetNodes ()
864+ if err != nil {
865+ logger .Errorf ("Could not get the nodes that belong to MCP %s: %s" , mcp .GetName (), err )
866+ return err
867+ }
868+
869+ label := fmt .Sprintf ("node-role.kubernetes.io/%s" , mcp .GetName ())
870+ for _ , node := range nodes {
871+ logger .Infof ("Removing pool label from node %s" , node .GetName ())
872+ err := node .RemoveLabel (label )
873+ if err != nil {
874+ logger .Errorf ("Could not remove the role label from node %s: %s" , node .GetName (), err )
875+ return err
876+ }
877+ }
878+
879+ for _ , node := range nodes {
880+ err := node .WaitForLabelRemoved (label )
881+ if err != nil {
882+ logger .Errorf ("The label %s was not removed from node %s" , label , node .GetName ())
883+ }
884+ }
885+
886+ err = mcp .WaitForMachineCount (0 , 5 * time .Minute )
887+ if err != nil {
888+ logger .Errorf ("The %s MCP already contains nodes, it cannot be deleted: %s" , mcp .GetName (), err )
889+ return err
890+ }
891+
892+ // Wait for worker MCP to be updated before removing the custom pool
893+ // in order to make sure that no node has any annotation pointing to resources that depend on the custom pool that we want to delete
894+ wMcp := NewMachineConfigPool (oc , MachineConfigPoolWorker )
895+ wMcp .waitForComplete ()
896+
897+ err = mcp .Delete ()
898+ if err != nil {
899+ logger .Errorf ("Could not delete %s MCP" , mcp .GetName ())
900+ return err
901+ }
902+
903+ return nil
904+ }
905+
906+ // GetPoolSynchronizersStatusByType returns the pool synchronizer status for a given type
907+ func (mcp * MachineConfigPool ) GetPoolSynchronizersStatusByType (pType string ) (string , error ) {
908+ return mcp .Get (`{.status.poolSynchronizersStatus[?(@.poolSynchronizerType=="` + pType + `")]}` )
909+ }
910+
911+ // IsPinnedImagesComplete returns if the MCP is reporting that there is no pinnedimages operation in progress
912+ func (mcp * MachineConfigPool ) IsPinnedImagesComplete () (bool , error ) {
913+
914+ pinnedStatus , err := mcp .GetPoolSynchronizersStatusByType ("PinnedImageSets" )
915+ if err != nil {
916+ return false , err
917+ }
918+
919+ logger .Infof ("Pinned status: %s" , pinnedStatus )
920+
921+ mcpMachineCount , err := mcp .Get (`{.status.machineCount}` )
922+ if err != nil {
923+ return false , err
924+ }
925+
926+ if mcpMachineCount == "" {
927+ return false , fmt .Errorf ("status.machineCount is empty in mcp %s" , mcp .GetName ())
928+ }
929+
930+ pinnedMachineCount := gjson .Get (pinnedStatus , "machineCount" ).String ()
931+ if pinnedMachineCount == "" {
932+ return false , fmt .Errorf ("pinned status machineCount is empty in mcp %s" , mcp .GetName ())
933+ }
934+
935+ pinnedUnavailableMachineCount := gjson .Get (pinnedStatus , "unavailableMachineCount" ).String ()
936+ if pinnedUnavailableMachineCount == "" {
937+ return false , fmt .Errorf ("pinned status unavailableMachineCount is empty in mcp %s" , mcp .GetName ())
938+ }
939+
940+ updatedMachineCount := gjson .Get (pinnedStatus , "updatedMachineCount" ).String ()
941+ if updatedMachineCount == "" {
942+ return false , fmt .Errorf ("pinned status updatedMachineCount is empty in mcp %s" , mcp .GetName ())
943+ }
944+
945+ return mcpMachineCount == pinnedMachineCount && updatedMachineCount == pinnedMachineCount && pinnedUnavailableMachineCount == "0" , nil
946+ }
947+
948+ // allNodesReportingPinnedSuccess returns true if all nodes in the pool are reporting pinned images success
949+ func (mcp * MachineConfigPool ) allNodesReportingPinnedSuccess () (bool , error ) {
950+ allNodes , err := mcp .GetNodes ()
951+ if err != nil {
952+ return false , err
953+ }
954+
955+ if len (allNodes ) == 0 {
956+ logger .Infof ("Warning, pool %s has no nodes!! We consider all nodes as correctly pinned" , mcp .GetName ())
957+ }
958+
959+ for _ , node := range allNodes {
960+ nodeMCN := node .GetMachineConfigNode ()
961+ if nodeMCN .IsPinnedImageSetsDegraded () {
962+ logger .Infof ("Node %s is pinned degraded. Condition:\n %s" , node .GetName (), nodeMCN .GetConditionByType ("PinnedImageSetsDegraded" ))
963+ return false , nil
964+ }
965+
966+ if nodeMCN .IsPinnedImageSetsProgressing () {
967+ return false , nil
968+ }
969+ }
970+
971+ return true , nil
972+ }
973+
974+ // waitForPinComplete waits for the MCP to complete pinning images
975+ func (mcp * MachineConfigPool ) waitForPinComplete (timeToWait time.Duration ) error {
976+ logger .Infof ("Waiting %s for MCP %s to complete pinned images." , timeToWait , mcp .name )
977+
978+ immediate := false
979+ err := wait .PollUntilContextTimeout (context .TODO (), 1 * time .Minute , timeToWait , immediate , func (_ context.Context ) (bool , error ) {
980+ pinnedComplete , err := mcp .IsPinnedImagesComplete ()
981+ if err != nil {
982+
983+ logger .Infof ("Error getting pinned complete: %s" , err )
984+ return false , err
985+ }
986+
987+ if ! pinnedComplete {
988+ logger .Infof ("Waiting for PinnedImageSets poolSynchronizersStatus status to repot success" )
989+ return false , nil
990+ }
991+
992+ allNodesComplete , err := mcp .allNodesReportingPinnedSuccess ()
993+ if err != nil {
994+ logger .Infof ("Error getting if all nodes finished" )
995+ return false , err
996+ }
997+
998+ if ! allNodesComplete {
999+ logger .Infof ("Waiting for all nodes to report pinned images success" )
1000+ return false , nil
1001+ }
1002+
1003+ logger .Infof ("Pool %s successfully pinned the images! Complete!" , mcp .GetName ())
1004+ return true , nil
1005+ })
1006+
1007+ if err != nil {
1008+ logger .Infof ("Pinned images operation is not completed on mcp %s" , mcp .name )
1009+ }
1010+ return err
1011+ }
1012+
1013+ // GetPinnedImageSets returns a list with the nodes that match the .spec.nodeSelector.matchLabels criteria plus the provided extraLabels
1014+ func (mcp * MachineConfigPool ) GetPinnedImageSets () ([]* PinnedImageSet , error ) {
1015+ mcp .oc .NotShowInfo ()
1016+ defer mcp .oc .SetShowInfo ()
1017+
1018+ labelsString , err := mcp .Get (`{.spec.machineConfigSelector.matchLabels}` )
1019+ if err != nil {
1020+ return nil , err
1021+ }
1022+
1023+ if labelsString == "" {
1024+ return nil , fmt .Errorf ("No machineConfigSelector found in %s" , mcp )
1025+ }
1026+
1027+ labels := gjson .Parse (labelsString )
1028+
1029+ requiredLabel := ""
1030+ labels .ForEach (func (key , value gjson.Result ) bool {
1031+ requiredLabel += fmt .Sprintf ("%s=%s," , key .String (), value .String ())
1032+ return true // keep iterating
1033+ })
1034+
1035+ if requiredLabel == "" {
1036+ return nil , fmt .Errorf ("No labels matcher could be built for %s" , mcp )
1037+ }
1038+ // remove the last comma
1039+ requiredLabel = strings .TrimSuffix (requiredLabel , "," )
1040+
1041+ pisList := NewPinnedImageSetList (mcp .oc )
1042+ pisList .ByLabel (requiredLabel )
1043+
1044+ return pisList .GetAll ()
1045+ }
0 commit comments