Skip to content

Commit c726ad8

Browse files
smarthallclaude
andauthored
[SREP-618] feat: Add refresh command to fetch config from server (#899)
* Add /config endpoint integration with lazy loading Implements client-side integration for the new /config API endpoint that allows backplane-cli to fetch server-managed configuration values. Features: - Refresh command: 'ocm backplane config refresh' to force update server values - Backwards compatible: Existing config files work without changes Implementation: - New ConfigAPIClient interface for fetching remote config - New refresh command to manually update server-managed values Server-managed values: - jira-base-url - assume-initial-arn - prod-env-name - jira-config-for-access-requests Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Verify the logging Signed-off-by: Daniel Hall <danhall@redhat.com> * Don't write empty jira values to config Signed-off-by: Daniel Hall <danhall@redhat.com> * Fix proxy support for config refresh command Use backplaneapi.DefaultClientUtils.GetBackplaneClient() instead of direct client creation to ensure proper proxy configuration and authentication. This fixes timeout issues when running behind corporate proxies. Signed-off-by: Daniel Hall <danhall@redhat.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Improve code quality in mapJiraAccessRequestConfig - Add early return to avoid wasteful allocation when config is empty - Extract magic strings to constants (transitionStateApproved, etc.) - Enhance documentation to clarify nil-return contract - Reuse hasTransitions variable to avoid duplicate checks These changes improve efficiency by preventing unnecessary struct and map allocations in the common case where the API returns empty config. Signed-off-by: Daniel Hall <danhall@redhat.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Fix test isolation for TestNoAutomaticConfigFetch Set BACKPLANE_CONFIG to a non-existent path in the test to prevent it from reading the user's actual config file. This ensures test isolation and prevents test failures when the user's config contains different values than the test expects. Signed-off-by: Daniel Hall <danhall@redhat.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Signed-off-by: Daniel Hall <danhall@redhat.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent e5e2e37 commit c726ad8

File tree

13 files changed

+1263
-10
lines changed

13 files changed

+1263
-10
lines changed

cmd/ocm-backplane/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ govcloud Set to true if used in FedRAMP
3232
cmd.AddCommand(newGetCmd())
3333
cmd.AddCommand(newSetCmd())
3434
cmd.AddCommand(newTroubleshootCmd())
35+
cmd.AddCommand(newRefreshCmd())
3536
return cmd
3637
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
"github.com/spf13/viper"
8+
9+
"github.com/openshift/backplane-cli/pkg/backplaneapi"
10+
"github.com/openshift/backplane-cli/pkg/cli/config"
11+
"github.com/openshift/backplane-cli/pkg/ocm"
12+
logger "github.com/sirupsen/logrus"
13+
)
14+
15+
func newRefreshCmd() *cobra.Command {
16+
cmd := &cobra.Command{
17+
Use: "refresh",
18+
Short: "Refresh configuration from backplane-api server",
19+
Long: `Fetch the latest configuration values from the backplane-api server and update the local config file.
20+
21+
This command will overwrite the following server-managed configuration values:
22+
- jira-base-url
23+
- assume-initial-arn
24+
- prod-env-name
25+
- jira-config-for-access-requests
26+
27+
User-defined values (proxy-url, session-dir, etc.) will not be modified.`,
28+
SilenceUsage: true,
29+
Args: cobra.NoArgs,
30+
RunE: runRefresh,
31+
}
32+
33+
return cmd
34+
}
35+
36+
func runRefresh(cmd *cobra.Command, args []string) error {
37+
logger.Info("Refreshing configuration from backplane-api...")
38+
39+
// Get current config to determine backplane URL
40+
bpConfig, err := config.GetBackplaneConfiguration()
41+
if err != nil {
42+
return fmt.Errorf("failed to load current configuration: %w", err)
43+
}
44+
45+
// Get OCM access token
46+
token, err := ocm.DefaultOCMInterface.GetOCMAccessToken()
47+
if err != nil {
48+
return fmt.Errorf("failed to get OCM access token: %w", err)
49+
}
50+
51+
// Create backplane API client with proper proxy support
52+
client, err := backplaneapi.DefaultClientUtils.GetBackplaneClient(bpConfig.URL, *token, bpConfig.ProxyURL)
53+
if err != nil {
54+
return fmt.Errorf("failed to create backplane API client: %w", err)
55+
}
56+
57+
// Fetch fresh config from API
58+
remoteConfig, err := config.DefaultAPIClient.FetchRemoteConfig(client)
59+
if err != nil {
60+
return fmt.Errorf("failed to fetch configuration from server: %w", err)
61+
}
62+
63+
// Get config file path
64+
configPath, err := config.GetConfigFilePath()
65+
if err != nil {
66+
return fmt.Errorf("failed to get config file path: %w", err)
67+
}
68+
69+
// Reset viper to clear any defaults that were set by GetBackplaneConfiguration
70+
// This prevents defaults like 'govcloud' from leaking into the user's config file
71+
viper.Reset()
72+
73+
// Load existing config file to preserve user settings
74+
viper.SetConfigFile(configPath)
75+
viper.SetConfigType("json")
76+
if err := viper.ReadInConfig(); err != nil {
77+
// If config doesn't exist, that's okay - we'll create it
78+
logger.Debugf("No existing config file found, will create new one")
79+
}
80+
81+
// Update only server-managed values
82+
updated := false
83+
if remoteConfig.JiraBaseURL != nil {
84+
viper.Set(config.JiraBaseURLKey, *remoteConfig.JiraBaseURL)
85+
logger.Infof("Updated jira-base-url: %s", *remoteConfig.JiraBaseURL)
86+
updated = true
87+
}
88+
89+
if remoteConfig.AssumeInitialArn != nil {
90+
viper.Set(config.AssumeInitialArnKey, *remoteConfig.AssumeInitialArn)
91+
logger.Infof("Updated assume-initial-arn: %s", *remoteConfig.AssumeInitialArn)
92+
updated = true
93+
}
94+
95+
if remoteConfig.ProdEnvName != nil {
96+
viper.Set(config.ProdEnvNameKey, *remoteConfig.ProdEnvName)
97+
logger.Infof("Updated prod-env-name: %s", *remoteConfig.ProdEnvName)
98+
updated = true
99+
}
100+
101+
if remoteConfig.JiraConfigForAccessRequests != nil {
102+
viper.Set(config.JiraConfigForAccessRequestsKey, remoteConfig.JiraConfigForAccessRequests)
103+
logger.Info("Updated jira-config-for-access-requests")
104+
updated = true
105+
}
106+
107+
if !updated {
108+
logger.Warn("No configuration values were returned from the server")
109+
}
110+
111+
// Write updated config to file
112+
if err := viper.WriteConfigAs(configPath); err != nil {
113+
return fmt.Errorf("failed to write config file: %w", err)
114+
}
115+
116+
fmt.Printf("Configuration refreshed successfully and saved to %s\n", configPath)
117+
return nil
118+
}

0 commit comments

Comments
 (0)