github.com/openshift/installer@v1.4.17/pkg/agent/ocp.go (about) 1 package agent 2 3 import ( 4 "context" 5 6 "github.com/pkg/errors" 7 "github.com/sirupsen/logrus" 8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 "k8s.io/client-go/rest" 10 "k8s.io/client-go/tools/clientcmd" 11 12 configv1 "github.com/openshift/api/config/v1" 13 configclient "github.com/openshift/client-go/config/clientset/versioned" 14 routeclient "github.com/openshift/client-go/route/clientset/versioned" 15 cov1helpers "github.com/openshift/library-go/pkg/config/clusteroperator/v1helpers" 16 "github.com/openshift/library-go/pkg/route/routeapihelpers" 17 ) 18 19 // ClusterOpenShiftAPIClient Kube client using the OpenShift clientset instead of the Kubernetes clientset 20 type ClusterOpenShiftAPIClient struct { 21 ConfigClient *configclient.Clientset 22 RouteClient *routeclient.Clientset 23 ctx context.Context 24 config *rest.Config 25 configPath string 26 cvResVersion string 27 } 28 29 const ( 30 // Need to keep these updated if they change 31 consoleNamespace = "openshift-console" 32 consoleRouteName = "console" 33 ) 34 35 // NewClusterOpenShiftAPIClient Create a kube client with OCP understanding 36 func NewClusterOpenShiftAPIClient(ctx context.Context, kubeconfigPath string) (*ClusterOpenShiftAPIClient, error) { 37 ocpClient := &ClusterOpenShiftAPIClient{} 38 39 var kubeconfig *rest.Config 40 var err error 41 if kubeconfigPath != "" { 42 kubeconfig, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath) 43 } else { 44 kubeconfig, err = rest.InClusterConfig() 45 } 46 if err != nil { 47 return nil, errors.Wrap(err, "creating kubeconfig for ocp config client") 48 } 49 50 configClient, err := configclient.NewForConfig(kubeconfig) 51 if err != nil { 52 return nil, errors.Wrap(err, "creating an ocp config client") 53 } 54 55 routeClient, err := routeclient.NewForConfig(kubeconfig) 56 if err != nil { 57 return nil, errors.Wrap(err, "creating an ocp route client") 58 } 59 60 ocpClient.ConfigClient = configClient 61 ocpClient.RouteClient = routeClient 62 ocpClient.ctx = ctx 63 ocpClient.config = kubeconfig 64 ocpClient.configPath = kubeconfigPath 65 66 return ocpClient, nil 67 } 68 69 // AreClusterOperatorsInitialized Waits for all Openshift cluster operators to initialize 70 func (ocp *ClusterOpenShiftAPIClient) AreClusterOperatorsInitialized() (bool, error) { 71 72 var lastError string 73 failing := configv1.ClusterStatusConditionType("Failing") 74 75 version, err := ocp.ConfigClient.ConfigV1().ClusterVersions().Get(ocp.ctx, "version", metav1.GetOptions{}) 76 if err != nil { 77 return false, errors.Wrap(err, "Getting ClusterVersion object") 78 } 79 80 if cov1helpers.IsStatusConditionTrue(version.Status.Conditions, configv1.OperatorAvailable) && 81 cov1helpers.IsStatusConditionFalse(version.Status.Conditions, failing) && 82 cov1helpers.IsStatusConditionFalse(version.Status.Conditions, configv1.OperatorProgressing) { 83 return true, nil 84 } 85 86 if cov1helpers.IsStatusConditionTrue(version.Status.Conditions, failing) { 87 lastError = cov1helpers.FindStatusCondition(version.Status.Conditions, failing).Message 88 } else if cov1helpers.IsStatusConditionTrue(version.Status.Conditions, configv1.OperatorProgressing) { 89 lastError = cov1helpers.FindStatusCondition(version.Status.Conditions, configv1.OperatorProgressing).Message 90 } 91 if version.ResourceVersion != ocp.cvResVersion { 92 logrus.Debugf("Still waiting for the cluster to initialize: %s", lastError) 93 ocp.cvResVersion = version.ResourceVersion 94 } 95 96 return false, nil 97 } 98 99 // IsConsoleRouteAvailable Check if the OCP console route is created 100 func (ocp *ClusterOpenShiftAPIClient) IsConsoleRouteAvailable() (bool, error) { 101 route, err := ocp.RouteClient.RouteV1().Routes(consoleNamespace).Get(ocp.ctx, consoleRouteName, metav1.GetOptions{}) 102 if err == nil { 103 logrus.Debugf("Route found in openshift-console namespace: %s", consoleRouteName) 104 if _, _, err2 := routeapihelpers.IngressURI(route, ""); err2 == nil { 105 logrus.Debug("OpenShift console route is admitted") 106 return true, nil 107 } else if err2 != nil { 108 err = err2 109 } 110 } 111 return false, errors.Wrap(err, "Waiting for openshift-console route") 112 } 113 114 // IsConsoleRouteURLAvailable Check if the console route URL is available 115 func (ocp *ClusterOpenShiftAPIClient) IsConsoleRouteURLAvailable() (bool, string, error) { 116 url := "" 117 route, err := ocp.RouteClient.RouteV1().Routes(consoleNamespace).Get(ocp.ctx, consoleRouteName, metav1.GetOptions{}) 118 if err == nil { 119 if uri, _, err2 := routeapihelpers.IngressURI(route, ""); err2 == nil { 120 url = uri.String() 121 } else { 122 err = err2 123 } 124 } 125 if url == "" { 126 return false, url, errors.Wrap(err, "Waiting for openshift-console URL") 127 } 128 return true, url, nil 129 } 130 131 // LogClusterOperatorConditions Log OCP cluster operator conditions 132 func (ocp *ClusterOpenShiftAPIClient) LogClusterOperatorConditions() error { 133 134 operators, err := ocp.ConfigClient.ConfigV1().ClusterOperators().List(ocp.ctx, metav1.ListOptions{}) 135 if err != nil { 136 return errors.Wrap(err, "Listing ClusterOperator objects") 137 } 138 139 for _, operator := range operators.Items { 140 for _, condition := range operator.Status.Conditions { 141 if condition.Type == configv1.OperatorUpgradeable { 142 continue 143 } else if condition.Type == configv1.OperatorAvailable && condition.Status == configv1.ConditionTrue { 144 continue 145 } else if (condition.Type == configv1.OperatorDegraded || condition.Type == configv1.OperatorProgressing) && condition.Status == configv1.ConditionFalse { 146 continue 147 } 148 if condition.Type == configv1.OperatorDegraded { 149 logrus.Errorf("Cluster operator %s %s is %s with %s: %s", operator.ObjectMeta.Name, condition.Type, condition.Status, condition.Reason, condition.Message) 150 } else { 151 logrus.Infof("Cluster operator %s %s is %s with %s: %s", operator.ObjectMeta.Name, condition.Type, condition.Status, condition.Reason, condition.Message) 152 } 153 } 154 } 155 156 return nil 157 }