Skip to content

Commit 54dbc7a

Browse files
authored
Migrate Jira auth to Atlassian Cloud and fix global viper race condition (#870)
* Update Jira auth and search API * Fix Jira config race condition caused by backplane-cli overwriting global viper
1 parent b0c2a8c commit 54dbc7a

File tree

7 files changed

+172
-54
lines changed

7 files changed

+172
-54
lines changed

cmd/cluster/context.go

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import (
3636
)
3737

3838
const (
39-
JiraBaseURL = "https://issues.redhat.com"
39+
JiraBaseURL = "https://redhat.atlassian.net"
4040
JiraTokenRegistrationPath = "/secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens" // #nosec G101
4141
PagerDutyTokenRegistrationUrl = "https://martindstone.github.io/PDOAuth/" // #nosec G101
4242
ClassicSplunkURL = "https://osdsecuritylogs.splunkcloud.com/en-US/app/search/search?q=search%%20index%%3D%%22%s%%22%%20clusterid%%3D%%22%s%%22\n\n"
@@ -362,6 +362,7 @@ func (o *contextOptions) printJsonOutput(data *contextData, w io.Writer) {
362362
func (o *contextOptions) generateContextData() (*contextData, []error) {
363363
data := &contextData{}
364364
var dataErrors []error
365+
var mu sync.Mutex
365366

366367
wg := sync.WaitGroup{}
367368

@@ -442,7 +443,9 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
442443
defer utils.StartDelayTracker(o.verbose, "Limited Support reasons").End()
443444
limitedSupportReasons, err := utils.GetClusterLimitedSupportReasons(ocmClient, o.clusterID)
444445
if err != nil {
446+
mu.Lock()
445447
dataErrors = append(dataErrors, fmt.Errorf("error while getting Limited Support status reasons: %v", err))
448+
mu.Unlock()
446449
} else {
447450
data.LimitedSupportReasons = append(data.LimitedSupportReasons, limitedSupportReasons...)
448451
}
@@ -452,22 +455,32 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
452455
defer wg.Done()
453456
defer utils.StartDelayTracker(o.verbose, "Service Logs").End()
454457
timeToCheckSvcLogs := time.Now().AddDate(0, 0, -o.days)
455-
data.ServiceLogs, err = servicelog.GetServiceLogsSince(o.clusterID, timeToCheckSvcLogs, false, false)
456-
if err != nil {
457-
dataErrors = append(dataErrors, fmt.Errorf("error while getting the service logs: %v", err))
458+
svcLogs, svcErr := servicelog.GetServiceLogsSince(o.clusterID, timeToCheckSvcLogs, false, false)
459+
if svcErr != nil {
460+
mu.Lock()
461+
dataErrors = append(dataErrors, fmt.Errorf("error while getting the service logs: %v", svcErr))
462+
mu.Unlock()
463+
} else {
464+
data.ServiceLogs = svcLogs
458465
}
459466
}
460467

461468
GetBannedUser := func() {
462469
defer wg.Done()
463470
defer utils.StartDelayTracker(o.verbose, "Check Banned User").End()
464-
subscription, err := utils.GetSubscription(ocmClient, data.ClusterID)
465-
if err != nil {
466-
dataErrors = append(dataErrors, fmt.Errorf("error while getting subscription %v", err))
471+
subscription, subErr := utils.GetSubscription(ocmClient, data.ClusterID)
472+
if subErr != nil {
473+
mu.Lock()
474+
dataErrors = append(dataErrors, fmt.Errorf("error while getting subscription %v", subErr))
475+
mu.Unlock()
476+
return
467477
}
468-
creator, err := utils.GetAccount(ocmClient, subscription.Creator().ID())
469-
if err != nil {
470-
dataErrors = append(dataErrors, fmt.Errorf("error while checking if user is banned %v", err))
478+
creator, accErr := utils.GetAccount(ocmClient, subscription.Creator().ID())
479+
if accErr != nil {
480+
mu.Lock()
481+
dataErrors = append(dataErrors, fmt.Errorf("error while checking if user is banned %v", accErr))
482+
mu.Unlock()
483+
return
471484
}
472485
data.UserBanned = creator.Banned()
473486
data.BanCode = creator.BanCode()
@@ -477,33 +490,48 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
477490
GetJiraIssues := func() {
478491
defer wg.Done()
479492
defer utils.StartDelayTracker(o.verbose, "Jira Issues").End()
480-
data.JiraIssues, err = utils.GetJiraIssuesForCluster(o.clusterID, o.externalClusterID, o.jiratoken)
481-
if err != nil {
482-
dataErrors = append(dataErrors, fmt.Errorf("error while getting the open jira tickets: %v", err))
493+
jiraIssues, jiraErr := utils.GetJiraIssuesForCluster(o.clusterID, o.externalClusterID, o.jiratoken)
494+
if jiraErr != nil {
495+
mu.Lock()
496+
dataErrors = append(dataErrors, fmt.Errorf("error while getting the open jira tickets: %v", jiraErr))
497+
mu.Unlock()
498+
} else {
499+
data.JiraIssues = jiraIssues
483500
}
484501
}
485502

486503
GetHandoverAnnouncements := func() {
487504
defer wg.Done()
488505
defer utils.StartDelayTracker(o.verbose, "Handover Announcements").End()
489-
org, err := utils.GetOrganization(ocmClient, o.clusterID)
490-
if err != nil {
491-
fmt.Printf("Failed to get Subscription for cluster %s - err: %q", o.clusterID, err)
506+
org, orgErr := utils.GetOrganization(ocmClient, o.clusterID)
507+
if orgErr != nil {
508+
mu.Lock()
509+
dataErrors = append(dataErrors, fmt.Errorf("error while getting organization for cluster %s: %v", o.clusterID, orgErr))
510+
mu.Unlock()
511+
return
492512
}
493513

494514
productID := o.cluster.Product().ID()
495-
data.HandoverAnnouncements, err = utils.GetRelatedHandoverAnnouncements(o.clusterID, o.externalClusterID, o.jiratoken, org.Name(), productID, o.cluster.Hypershift().Enabled(), o.cluster.Version().RawID())
496-
if err != nil {
497-
dataErrors = append(dataErrors, fmt.Errorf("error while getting the open jira tickets: %v", err))
515+
announcements, haErr := utils.GetRelatedHandoverAnnouncements(o.clusterID, o.externalClusterID, o.jiratoken, org.Name(), productID, o.cluster.Hypershift().Enabled(), o.cluster.Version().RawID())
516+
if haErr != nil {
517+
mu.Lock()
518+
dataErrors = append(dataErrors, fmt.Errorf("error while getting handover announcements: %v", haErr))
519+
mu.Unlock()
520+
} else {
521+
data.HandoverAnnouncements = announcements
498522
}
499523
}
500524

501525
GetSupportExceptions := func() {
502526
defer wg.Done()
503527
defer utils.StartDelayTracker(o.verbose, "Support Exceptions").End()
504-
data.SupportExceptions, err = utils.GetJiraSupportExceptionsForOrg(o.organizationID, o.jiratoken)
505-
if err != nil {
506-
dataErrors = append(dataErrors, fmt.Errorf("error while getting support exceptions: %v", err))
528+
exceptions, seErr := utils.GetJiraSupportExceptionsForOrg(o.organizationID, o.jiratoken)
529+
if seErr != nil {
530+
mu.Lock()
531+
dataErrors = append(dataErrors, fmt.Errorf("error while getting support exceptions: %v", seErr))
532+
mu.Unlock()
533+
} else {
534+
data.SupportExceptions = exceptions
507535
}
508536
}
509537

@@ -517,28 +545,35 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
517545
if errors.Is(err, dynatrace.ErrUnsupportedCluster) {
518546
data.DyntraceEnvURL = dynatrace.ErrUnsupportedCluster.Error()
519547
} else {
548+
mu.Lock()
520549
dataErrors = append(dataErrors, fmt.Errorf("failed to acquire cluster details %v", err))
550+
mu.Unlock()
521551
data.DyntraceEnvURL = "Failed to fetch Dynatrace URL"
522552
}
523553
return
524554
}
525555
query, err := dynatrace.GetQuery(hcpCluster, time.Time{}, time.Time{}, 1) // passing nil from/to values to use --since behaviour
526556
if err != nil {
557+
mu.Lock()
527558
dataErrors = append(dataErrors, fmt.Errorf("failed to build query for Dynatrace %v", err))
559+
mu.Unlock()
528560
data.DyntraceEnvURL = fmt.Sprintf("Failed to build Dynatrace query: %v", err)
529561
return
530562
}
531563
queryTxt := query.Build()
532564
data.DyntraceEnvURL = hcpCluster.DynatraceURL
533-
data.DyntraceLogsURL, err = dynatrace.GetLinkToWebConsole(hcpCluster.DynatraceURL, "now()-10h", "now()", queryTxt)
534-
if err != nil {
535-
dataErrors = append(dataErrors, fmt.Errorf("failed to get url: %v", err))
565+
logsURL, dtErr := dynatrace.GetLinkToWebConsole(hcpCluster.DynatraceURL, "now()-10h", "now()", queryTxt)
566+
if dtErr != nil {
567+
mu.Lock()
568+
dataErrors = append(dataErrors, fmt.Errorf("failed to get url: %v", dtErr))
569+
mu.Unlock()
570+
} else {
571+
data.DyntraceLogsURL = logsURL
536572
}
537573

538574
}
539575

540576
GetPagerDutyAlerts := func() {
541-
pdwg.Add(1)
542577
defer wg.Done()
543578
defer pdwg.Done()
544579

@@ -547,16 +582,23 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
547582
}
548583

549584
delayTracker := utils.StartDelayTracker(o.verbose, "PagerDuty Service")
550-
data.pdServiceID, err = pdProvider.GetPDServiceIDs()
551-
if err != nil {
552-
dataErrors = append(dataErrors, fmt.Errorf("error getting PD Service ID: %v", err))
585+
pdServiceID, pdErr := pdProvider.GetPDServiceIDs()
586+
if pdErr != nil {
587+
mu.Lock()
588+
dataErrors = append(dataErrors, fmt.Errorf("error getting PD Service ID: %v", pdErr))
589+
mu.Unlock()
553590
}
591+
data.pdServiceID = pdServiceID
554592
delayTracker.End()
555593

556594
defer utils.StartDelayTracker(o.verbose, "current PagerDuty Alerts").End()
557-
data.PdAlerts, err = pdProvider.GetFiringAlertsForCluster(data.pdServiceID)
558-
if err != nil {
559-
dataErrors = append(dataErrors, fmt.Errorf("error while getting current PD Alerts: %v", err))
595+
pdAlerts, paErr := pdProvider.GetFiringAlertsForCluster(data.pdServiceID)
596+
if paErr != nil {
597+
mu.Lock()
598+
dataErrors = append(dataErrors, fmt.Errorf("error while getting current PD Alerts: %v", paErr))
599+
mu.Unlock()
600+
} else {
601+
data.PdAlerts = pdAlerts
560602
}
561603
}
562604

@@ -566,7 +608,9 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
566608

567609
migrationResponse, err := utils.GetMigration(ocmClient, o.clusterID)
568610
if err != nil {
611+
mu.Lock()
569612
dataErrors = append(dataErrors, fmt.Errorf("error while getting migration info: %v", err))
613+
mu.Unlock()
570614
return
571615
}
572616

@@ -586,13 +630,19 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
586630

587631
backplaneClient, er := backplane.NewClient(o.clusterID)
588632
if er != nil {
633+
mu.Lock()
589634
dataErrors = append(dataErrors, fmt.Errorf("error while creating backplane-api client: %v", er))
635+
mu.Unlock()
590636
return
591637
}
592638

593-
data.clusterReports, err = backplaneClient.ListReports(context.Background(), 0)
594-
if err != nil {
595-
dataErrors = append(dataErrors, fmt.Errorf("error while fetching cluster reports: %v", err))
639+
reports, crErr := backplaneClient.ListReports(context.Background(), 0)
640+
if crErr != nil {
641+
mu.Lock()
642+
dataErrors = append(dataErrors, fmt.Errorf("error while fetching cluster reports: %v", crErr))
643+
mu.Unlock()
644+
} else {
645+
data.clusterReports = reports
596646
}
597647
}
598648

@@ -638,18 +688,26 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
638688
pdwg.Wait()
639689
defer wg.Done()
640690
defer utils.StartDelayTracker(o.verbose, "historical PagerDuty Alerts").End()
641-
data.HistoricalAlerts, err = pdProvider.GetHistoricalAlertsForCluster(data.pdServiceID)
642-
if err != nil {
643-
dataErrors = append(dataErrors, fmt.Errorf("error while getting historical PD Alert Data: %v", err))
691+
histAlerts, haErr := pdProvider.GetHistoricalAlertsForCluster(data.pdServiceID)
692+
if haErr != nil {
693+
mu.Lock()
694+
dataErrors = append(dataErrors, fmt.Errorf("error while getting historical PD Alert Data: %v", haErr))
695+
mu.Unlock()
696+
} else {
697+
data.HistoricalAlerts = histAlerts
644698
}
645699
}
646700

647701
GetCloudTrailLogs := func() {
648702
defer wg.Done()
649703
defer utils.StartDelayTracker(o.verbose, fmt.Sprintf("past %d pages of Cloudtrail data", o.pages)).End()
650-
data.CloudtrailEvents, err = GetCloudTrailLogsForCluster(o.awsProfile, o.clusterID, o.pages)
651-
if err != nil {
652-
dataErrors = append(dataErrors, fmt.Errorf("error getting cloudtrail logs for cluster: %v", err))
704+
ctEvents, ctErr := GetCloudTrailLogsForCluster(o.awsProfile, o.clusterID, o.pages)
705+
if ctErr != nil {
706+
mu.Lock()
707+
dataErrors = append(dataErrors, fmt.Errorf("error getting cloudtrail logs for cluster: %v", ctErr))
708+
mu.Unlock()
709+
} else {
710+
data.CloudtrailEvents = ctEvents
653711
}
654712
}
655713

@@ -660,6 +718,10 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
660718
)
661719
}
662720

721+
// Add to pdwg before launching goroutines so pdwg.Wait() in
722+
// GetHistoricalPagerDutyAlerts doesn't race with pdwg.Add(1).
723+
pdwg.Add(1)
724+
663725
for _, retriever := range retrievers {
664726
wg.Add(1)
665727
go retriever()

cmd/cluster/context_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ func TestPrintJIRASupportExceptions(t *testing.T) {
326326
output := buf.String()
327327

328328
expectedStrings := []string{
329-
"- Link: https://issues.redhat.com/browse/JIRA-123",
329+
"- Link: https://redhat.atlassian.net/browse/JIRA-123",
330330
}
331331

332332
for _, expected := range expectedStrings {

docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,7 @@ osdctl cluster context --cluster-id <cluster-identifier> [flags]
14001400
-h, --help help for context
14011401
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
14021402
--jiratoken jira_token Pass in the Jira access token directly. If not passed in, by default will read jira_token from ~/.config/osdctl.
1403-
Jira access tokens can be registered by visiting https://issues.redhat.com//secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens
1403+
Jira access tokens can be registered by visiting https://redhat.atlassian.net//secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens
14041404
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
14051405
--oauthtoken pd_oauth_token Pass in PD oauthtoken directly. If not passed in, by default will read pd_oauth_token from ~/.config/osdctl.
14061406
PD OAuth tokens can be generated by visiting https://martindstone.github.io/PDOAuth/

docs/osdctl_cluster_context.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ osdctl cluster context --cluster-id <cluster-identifier> [flags]
1414
--full Run full suite of checks.
1515
-h, --help help for context
1616
--jiratoken jira_token Pass in the Jira access token directly. If not passed in, by default will read jira_token from ~/.config/osdctl.
17-
Jira access tokens can be registered by visiting https://issues.redhat.com//secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens
17+
Jira access tokens can be registered by visiting https://redhat.atlassian.net//secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens
1818
--oauthtoken pd_oauth_token Pass in PD oauthtoken directly. If not passed in, by default will read pd_oauth_token from ~/.config/osdctl.
1919
PD OAuth tokens can be generated by visiting https://martindstone.github.io/PDOAuth/
2020
-o, --output string Valid formats are ['long', 'short', 'json']. Output is set to 'long' by default (default "long")

pkg/osdctlConfig/osdctlConfig.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,27 @@ func EnsureConfigFile() error {
3737
}
3838
return nil
3939
}
40+
41+
// GetConfigValues reads the osdctl config file using a dedicated viper instance,
42+
// avoiding the global viper which backplane-cli overwrites concurrently.
43+
// TODO: Remove this workaround once backplane-cli stops overwriting the global viper instance.
44+
func GetConfigValues(keys ...string) (map[string]string, error) {
45+
configHomePath, err := os.UserHomeDir()
46+
if err != nil {
47+
return nil, err
48+
}
49+
configFilePath := configHomePath + "/.config/" + ConfigFileName
50+
51+
v := viper.New()
52+
v.SetConfigFile(configFilePath)
53+
v.SetConfigType("yaml")
54+
if err := v.ReadInConfig(); err != nil {
55+
return nil, err
56+
}
57+
58+
values := make(map[string]string, len(keys))
59+
for _, k := range keys {
60+
values[k] = v.GetString(k)
61+
}
62+
return values, nil
63+
}

0 commit comments

Comments
 (0)