Skip to content

Commit

Permalink
Merge pull request #538 from AlexVulaj/validate-pull-secret-no-manage…
Browse files Browse the repository at this point in the history
…d-script

Don't use managed scripts for validating pull secret
  • Loading branch information
openshift-merge-bot[bot] authored Mar 22, 2024
2 parents bac5b2c + 980eb8e commit 981cb82
Showing 1 changed file with 3 additions and 130 deletions.
133 changes: 3 additions & 130 deletions cmd/cluster/validatepullsecret.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ package cluster
import (
"context"
"fmt"
"os"
"os/exec"
"regexp"
"strings"
"time"

v1 "github.com/openshift-online/ocm-sdk-go/accountsmgmt/v1"
"github.com/openshift/osdctl/cmd/servicelog"
"github.com/openshift/osdctl/pkg/k8s"
Expand All @@ -17,6 +11,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"os"
)

var BackplaneClusterAdmin = "backplane-cluster-admin"
Expand All @@ -37,10 +32,6 @@ func newCmdValidatePullSecret(kubeCli *k8s.LazyClient) *cobra.Command {
Long: `Checks if the pull secret email matches the owner email.
The owner's email to check will be determined by the cluster identifier passed to the command, while the pull secret checked will be determined by the cluster that the caller is currently logged in to.
By default, it will run a managed-script in the cluster to get the pull-secret's email in the cluster.
In case the managed-script fails, --elevate can be added to get the pull-secret in the cluster directly without a managed-script.
`,
Args: cobra.ExactArgs(1),
DisableAutoGenTag: true,
Expand All @@ -49,9 +40,8 @@ In case the managed-script fails, --elevate can be added to get the pull-secret
cmdutil.CheckErr(ops.run())
},
}
validatePullSecretCmd.Flags().BoolVar(&ops.elevate, "elevate", false, "get pull-secret with backplane-cluster-admin without running a managed-script, mandatory when a reason is provided")
validatePullSecretCmd.Flags().StringVar(&ops.reason, "reason", "", "The reason for this command to be run (usualy an OHSS or PD ticket), mandatory when using elevate")
validatePullSecretCmd.MarkFlagsRequiredTogether("elevate", "reason")
_ = validatePullSecretCmd.MarkFlagRequired("reason")
return validatePullSecretCmd
}

Expand All @@ -72,7 +62,7 @@ func (o *validatePullSecretOptions) run() error {
}

// get the pull secret in cluster
emailCluster, err, done := o.getPullSecretFromCluster()
emailCluster, err, done := getPullSecretElevated(o.clusterID, o.kubeCli, o.reason)
if err != nil {
return err
}
Expand All @@ -93,32 +83,6 @@ func (o *validatePullSecretOptions) run() error {
return nil
}

func (o *validatePullSecretOptions) getPullSecretFromCluster() (email string, err error, sentSL bool) {
if o.elevate {
return getPullSecretElevated(o.clusterID, o.kubeCli, o.reason)
} else {
return getPullSecretManagedScript(o.clusterID)
}
}

// getPullSecretManagedScript runs a managed-script to get the pull-secret
// email from cluster without backplane elevation
// it returns the email, error and sentSL
// sentSL=true means a SL has been send to the cluster
func getPullSecretManagedScript(clusterID string) (email string, err error, sentSL bool) {
jobId, err := createManagedJob()
if err != nil {
return "", err, false
}
err, sentSL = waitManagedJob(jobId, clusterID)
if sentSL || err != nil {
return "", err, sentSL
}
email, err = getManagedJobResult(jobId)

return email, err, false
}

// getPullSecretElevated gets the pull-secret in the cluster
// with backplane elevation.
func getPullSecretElevated(clusterID string, kubeCli *k8s.LazyClient, reason string) (email string, err error, sentSL bool) {
Expand All @@ -138,97 +102,6 @@ func getPullSecretElevated(clusterID string, kubeCli *k8s.LazyClient, reason str
return clusterPullSecretEmail, nil, false
}

// createManagedJob creates a managed job to get the pull-secret email inside the cluster
func createManagedJob() (jobId string, err error) {
fmt.Println("Creating a managedjob to get pull-secret email in the cluster")
createJobCmd := "ocm backplane managedjob create SREP/get-pull-secret-email"
createJobOutput, err := exec.Command("bash", "-c", createJobCmd).CombinedOutput()
if err != nil {
return "", fmt.Errorf("failed to run managed script SREP/get-pull-secret-email:\n%s", strings.TrimSpace(string(createJobOutput)))
}
// Get the job id from output
re := regexp.MustCompile(`openshift-job-[a-z0-9]+`)
matches := re.FindStringSubmatch(string(createJobOutput))
if len(matches) == 0 {
return "", fmt.Errorf("failed to find job id after creating managedjob")
}
jobId = matches[0]
fmt.Printf("managedjob id: %s\n", jobId)
return jobId, nil
}

// waitManagedJob waits for the managedjob to finish
// if there's a timeout, it will check the reason for timeout and send SL
// if timeout reason unknown, it returns an error.
func waitManagedJob(jobId string, clusterID string) (err error, sentSL bool) {
fmt.Println("Waiting for managedjob to finish, it usually takes 30s")
getJobStatusCmd := fmt.Sprintf("ocm backplane managedjob get %s", jobId)
re := regexp.MustCompile(`Succeeded`)
matches := []string{}
// wait 10x10 seconds to finish
for i := 0; i < 10; i++ {
getJobStatusOutput, err := exec.Command("bash", "-c", getJobStatusCmd).CombinedOutput()
if err != nil {
continue
}
matches = re.FindStringSubmatch(string(getJobStatusOutput))
if len(matches) > 0 {
break
}
time.Sleep(10 * time.Second)
}

// managedjob succeed
if len(matches) > 0 {
return nil, false
}

// managedjob timeout, check the error.
// instead of the go native way to get events:
// https://github.com/openshift/oc/blob/c7b582ed27cfb2890068d6cb29cb2f5b936654cd/vendor/k8s.io/kubectl/pkg/describe/describe.go#L4258
// we can simply run the oc describe command and match the output.
describeJobCmd := fmt.Sprintf("oc describe pod %s -n openshift-backplane-managed-scripts", jobId)
describeJobOutput, err := exec.Command("bash", "-c", describeJobCmd).CombinedOutput()
if err != nil {
return fmt.Errorf("failed to execute: %s: %w", describeJobCmd, err), false
}
re = regexp.MustCompile(`unauthorized`)
matches = re.FindStringSubmatch(string(describeJobOutput))
if len(matches) > 0 {
fmt.Printf("managedjob failed due to failed authentication to pull image, run the below command for more detail:\n%s\n", describeJobCmd)
fmt.Println("Sending service log")
postCmd := servicelog.PostCmdOptions{
Template: "https://raw.githubusercontent.com/openshift/managed-notifications/master/osd/pull_secret_change_breaking_upgradesync.json",
ClusterId: clusterID,
}
if err = postCmd.Run(); err != nil {
return err, true
}
return nil, true
}
return fmt.Errorf("managedjob timeout, try --elevate to validate pull-secret without a managed job"), false
}

// getManagedJobResult return's the email address fetched by the managedjob
func getManagedJobResult(jobId string) (string, error) {
// Get the output of the managed script
getJobResultCmd := fmt.Sprintf("ocm backplane managedjob logs %s", jobId)
getJobResultOutput, err := exec.Command("bash", "-c", getJobResultCmd).CombinedOutput()
if err != nil {
return "", fmt.Errorf("failed to get the output of %s:%s", jobId, strings.TrimSpace(string(getJobResultOutput)))
}

re := regexp.MustCompile(`@`)
matches := re.FindStringSubmatch(string(getJobResultOutput))
if len(matches) == 0 {
return "", fmt.Errorf("not a valid email output from the managed-script, output: %s", string(getJobResultOutput))
}
email := strings.TrimSpace(string(getJobResultOutput))
fmt.Printf("email from managedjob: %s\n", email)

return string(email), nil
}

// getPullSecretFromOCM gets the cluster owner email from OCM
// it returns the email, error and done
// done means a service log has been sent
Expand Down

0 comments on commit 981cb82

Please sign in to comment.