-
Notifications
You must be signed in to change notification settings - Fork 1.5k
AGENT-580: Add agent gather bootstrap command #10666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| package agent | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "time" | ||
|
|
||
| "github.com/sirupsen/logrus" | ||
| "github.com/spf13/cobra" | ||
|
|
||
| "github.com/openshift/installer/cmd/openshift-install/command" | ||
| agentpkg "github.com/openshift/installer/pkg/agent" | ||
| assetstore "github.com/openshift/installer/pkg/asset/store" | ||
| "github.com/openshift/installer/pkg/asset/tls" | ||
| ) | ||
|
|
||
| var agentGatherOpts struct { | ||
| sshKeys []string | ||
| } | ||
|
|
||
| // NewGatherCmd creates the commands for gathering debug data from an agent-based installation. | ||
| func NewGatherCmd() *cobra.Command { | ||
| cmd := &cobra.Command{ | ||
| Use: "gather", | ||
| Short: "Gather debugging data for a failed agent-based installation", | ||
| Long: `Gather debugging data for a failed agent-based installation. | ||
|
|
||
| When an agent-based installation fails, this command collects debugging | ||
| data from the rendezvous host to help diagnose the issue.`, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| return cmd.Help() | ||
| }, | ||
| } | ||
|
|
||
| cmd.AddCommand(newAgentGatherCmd()) | ||
| return cmd | ||
| } | ||
|
|
||
| func newAgentGatherCmd() *cobra.Command { | ||
| cmd := &cobra.Command{ | ||
| Use: "bootstrap", | ||
| Short: "Gather debugging data from the rendezvous host", | ||
| Args: cobra.ExactArgs(0), | ||
| Run: func(_ *cobra.Command, _ []string) { | ||
| cleanup := command.SetupFileHook(command.RootOpts.Dir) | ||
| defer cleanup() | ||
|
|
||
| bundlePath, err := runAgentGatherCmd(command.RootOpts.Dir) | ||
| if err != nil { | ||
| logrus.Fatal(err) | ||
| } | ||
| logrus.Infof("Agent gather logs captured here %q", bundlePath) | ||
| }, | ||
| } | ||
|
|
||
| cmd.PersistentFlags().StringArrayVar(&agentGatherOpts.sshKeys, "key", []string{}, | ||
| "Path to SSH private keys that should be used for authentication. "+ | ||
| "If no key was provided, SSH private keys from user's environment will be used") | ||
| return cmd | ||
| } | ||
|
|
||
| func runAgentGatherCmd(directory string) (string, error) { | ||
| ctx := context.TODO() | ||
|
|
||
| store, err := assetstore.NewStore(directory) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to create asset store: %w", err) | ||
| } | ||
|
|
||
| rendezvousIP, err := agentpkg.FindRendezvousIPFromAssetStore(store) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to determine rendezvous host: %w", err) | ||
| } | ||
| logrus.Infof("Rendezvous host IP: %s", rendezvousIP) | ||
|
|
||
| // add the bootstrap SSH key pair to the sshKeys list automatically | ||
| bootstrapSSHKeyPair := &tls.BootstrapSSHKeyPair{} | ||
| if err := store.Fetch(ctx, bootstrapSSHKeyPair); err != nil { | ||
| logrus.Debugf("Failed to fetch bootstrap SSH key pair: %v", err) | ||
| } else { | ||
| tmpfile, err := os.CreateTemp("", "bootstrap-ssh") | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| defer os.Remove(tmpfile.Name()) | ||
| if _, err := tmpfile.Write(bootstrapSSHKeyPair.Private()); err != nil { | ||
| return "", err | ||
| } | ||
| if err := tmpfile.Close(); err != nil { | ||
| return "", err | ||
| } | ||
| agentGatherOpts.sshKeys = append(agentGatherOpts.sshKeys, tmpfile.Name()) | ||
| } | ||
|
Comment on lines
+77
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Avoid persisting a deleted temp-key path in global options. Line 93 appends the temp key path to package-level Proposed fix+ sshKeys := append([]string{}, agentGatherOpts.sshKeys...)
+
// add the bootstrap SSH key pair to the sshKeys list automatically
bootstrapSSHKeyPair := &tls.BootstrapSSHKeyPair{}
if err := store.Fetch(ctx, bootstrapSSHKeyPair); err != nil {
logrus.Debugf("Failed to fetch bootstrap SSH key pair: %v", err)
@@
- agentGatherOpts.sshKeys = append(agentGatherOpts.sshKeys, tmpfile.Name())
+ sshKeys = append(sshKeys, tmpfile.Name())
}
gatherID := time.Now().Format("20060102150405")
- bundlePath, err := agentpkg.PullAgentGatherArchive(rendezvousIP, agentGatherOpts.sshKeys, directory, gatherID)
+ bundlePath, err := agentpkg.PullAgentGatherArchive(rendezvousIP, sshKeys, directory, gatherID)Also applies to: 98-98 🤖 Prompt for AI Agents |
||
|
|
||
| gatherID := time.Now().Format("20060102150405") | ||
|
|
||
| bundlePath, err := agentpkg.PullAgentGatherArchive(rendezvousIP, agentGatherOpts.sshKeys, directory, gatherID) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to gather data from rendezvous host: %w", err) | ||
| } | ||
|
|
||
| return bundlePath, nil | ||
|
Comment on lines
+40
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify tests cover the new gather command/helper wiring without assuming file layout.
rg -n --glob '*_test.go' 'NewGatherCmd|newAgentGatherCmd|runAgentGatherCmd|PullAgentGatherArchive'Repository: openshift/installer Length of output: 157 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Map the relevant command package and locate related tests.
git ls-files 'cmd/openshift-install/agent/*' 'cmd/openshift-install/*_test.go' | sort
echo '--- outline gather.go ---'
ast-grep outline cmd/openshift-install/agent/gather.go --view expanded || true
echo '--- search for agent gather tests and related helpers ---'
rg -n --glob 'cmd/openshift-install/**/*_test.go' \
'gather|Rendezvous|BootstrapSSHKeyPair|PullAgentGatherArchive|newAgentGatherCmd|runAgentGatherCmd|agentGatherOpts'
echo '--- search for command setup tests elsewhere ---'
rg -n --glob '**/*_test.go' \
'SetupFileHook|PullAgentGatherArchive|FindRendezvousIPFromAssetStore|BootstrapSSHKeyPair'Repository: openshift/installer Length of output: 757 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Enumerate unit-test files in cmd/openshift-install and look for command-path coverage.
git ls-files 'cmd/openshift-install/**/*_test.go' | sort
echo '--- command-related test coverage ---'
rg -n --glob 'cmd/openshift-install/**/*_test.go' \
'New.*Cmd|new.*Cmd|run.*Cmd|gather|waitfor|agent' \
cmd/openshift-installRepository: openshift/installer Length of output: 472 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the existing cmd/openshift-install tests to see whether they are unit tests
# and whether they exercise the new gather command path.
ast-grep outline cmd/openshift-install/integration_test.go --view expanded || true
echo '---'
ast-grep outline cmd/openshift-install/internal_integration_test.go --view expanded || true
echo '--- file headers ---'
sed -n '1,140p' cmd/openshift-install/integration_test.go
echo '---'
sed -n '1,180p' cmd/openshift-install/internal_integration_test.goRepository: openshift/installer Length of output: 6415 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check the test file kinds and whether they import testing-only integration deps.
for f in cmd/openshift-install/integration_test.go cmd/openshift-install/internal_integration_test.go; do
echo "--- $f ---"
sed -n '1,120p' "$f"
doneRepository: openshift/installer Length of output: 4164 Add unit tests for the agent gather command path 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package agent | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "net" | ||
| "path" | ||
| "path/filepath" | ||
| "strconv" | ||
|
|
||
| "github.com/sirupsen/logrus" | ||
|
|
||
| gatherssh "github.com/openshift/installer/pkg/gather/ssh" | ||
| ) | ||
|
|
||
| // PullAgentGatherArchive SSHs to the rendezvous host and runs the | ||
| // agent-gather script, pulling the resulting tar.xz archive to the | ||
| // local directory. | ||
| func PullAgentGatherArchive(rendezvousIP string, sshKeys []string, directory, gatherID string) (string, error) { | ||
| logrus.Info("Pulling agent-gather data from the rendezvous host") | ||
|
|
||
| address := net.JoinHostPort(rendezvousIP, strconv.Itoa(22)) | ||
| client, err := gatherssh.NewClient("core", address, sshKeys) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to create SSH client for rendezvous host %s: %w", rendezvousIP, err) | ||
| } | ||
|
|
||
| // Run agent-gather with -i so it writes to a predictable path | ||
| cmd := fmt.Sprintf("sudo /usr/local/bin/agent-gather -i %s", gatherID) | ||
| if err := gatherssh.Run(client, cmd); err != nil { | ||
| return "", fmt.Errorf("failed to run agent-gather on rendezvous host %s: %w", rendezvousIP, err) | ||
| } | ||
|
|
||
| archiveName := fmt.Sprintf("agent-gather-%s.tar.xz", gatherID) | ||
| remoteFile := path.Join("/home/core", archiveName) | ||
| localFile := filepath.Join(directory, archiveName) | ||
| if err := gatherssh.PullFileTo(client, remoteFile, localFile); err != nil { | ||
| return "", fmt.Errorf("failed to pull agent-gather archive: %w", err) | ||
| } | ||
|
|
||
| absPath, err := filepath.Abs(localFile) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to get absolute path: %w", err) | ||
| } | ||
|
|
||
| logrus.Info("Successfully pulled agent-gather data") | ||
| return absPath, nil | ||
| } | ||
|
Comment on lines
+18
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
ast-grep outline pkg/gather/ssh
rg -n -A5 'func NewClient|func Run|func PullFileTo' pkg/gather/sshRepository: openshift/installer Length of output: 1335 🏁 Script executed: #!/bin/bash
sed -n '1,220p' pkg/gather/ssh/ssh.goRepository: openshift/installer Length of output: 4360 Add a timeout to the SSH gather path. 🤖 Prompt for AI AgentsSource: Path instructions |
||
Uh oh!
There was an error while loading. Please reload this page.