@@ -30,84 +30,125 @@ type Image struct {
3030}
3131
3232func ValidateInstanceImage (ctx context.Context , instance Instance , privateKey string ) error {
33- // First ensure the instance is running and SSH accessible
34- sshUser := instance .SSHUser
35- sshPort := instance .SSHPort
36- publicIP := instance .PublicIP
33+ sshClient , err := connectToInstance (ctx , instance , privateKey )
34+ if err != nil {
35+ return err
36+ }
37+ defer func () {
38+ if closeErr := sshClient .Close (); closeErr != nil {
39+ fmt .Printf ("warning: failed to close SSH connection: %v\n " , closeErr )
40+ }
41+ }()
42+
43+ arch , err := validateArchitecture (ctx , sshClient )
44+ if err != nil {
45+ return err
46+ }
47+
48+ osVersion , err := validateOSVersion (ctx , sshClient )
49+ if err != nil {
50+ return err
51+ }
52+
53+ homeDir , err := validateHomeDirectory (ctx , sshClient , instance .SSHUser )
54+ if err != nil {
55+ return err
56+ }
57+
58+ systemdStatus , err := validateSystemd (ctx , sshClient )
59+ if err != nil {
60+ return err
61+ }
3762
38- // Validate that we have the required SSH connection details
39- if sshUser == "" {
40- return fmt .Errorf ("SSH user is not set for instance %s" , instance .CloudID )
63+ fmt .Printf ("Instance image validation passed for %s: architecture=%s, os=%s, home=%s, systemd=%s\n " ,
64+ instance .CloudID , arch , osVersion , homeDir , systemdStatus )
65+
66+ return nil
67+ }
68+
69+ func connectToInstance (ctx context.Context , instance Instance , privateKey string ) (* ssh.Client , error ) {
70+ if instance .SSHUser == "" {
71+ return nil , fmt .Errorf ("SSH user is not set for instance %s" , instance .CloudID )
4172 }
42- if sshPort == 0 {
43- return fmt .Errorf ("SSH port is not set for instance %s" , instance .CloudID )
73+ if instance . SSHPort == 0 {
74+ return nil , fmt .Errorf ("SSH port is not set for instance %s" , instance .CloudID )
4475 }
45- if publicIP == "" {
46- return fmt .Errorf ("public IP is not available for instance %s" , instance .CloudID )
76+ if instance . PublicIP == "" {
77+ return nil , fmt .Errorf ("public IP is not available for instance %s" , instance .CloudID )
4778 }
4879
49- // Connect to the instance via SSH
5080 sshClient , err := ssh .ConnectToHost (ctx , ssh.ConnectionConfig {
51- User : sshUser ,
52- HostPort : fmt .Sprintf ("%s:%d" , publicIP , sshPort ),
81+ User : instance . SSHUser ,
82+ HostPort : fmt .Sprintf ("%s:%d" , instance . PublicIP , instance . SSHPort ),
5383 PrivKey : privateKey ,
5484 })
5585 if err != nil {
56- return fmt .Errorf ("failed to connect to instance via SSH: %w" , err )
86+ return nil , fmt .Errorf ("failed to connect to instance via SSH: %w" , err )
5787 }
58- defer func () {
59- if closeErr := sshClient .Close (); closeErr != nil {
60- // Log close error but don't return it as it's not the primary error
61- fmt .Printf ("warning: failed to close SSH connection: %v\n " , closeErr )
62- }
63- }()
88+ return sshClient , nil
89+ }
6490
65- // Check 1: Verify x86_64 architecture
91+ func validateArchitecture ( ctx context. Context , sshClient * ssh. Client ) ( string , error ) {
6692 stdout , stderr , err := sshClient .RunCommand (ctx , "uname -m" )
6793 if err != nil {
68- return fmt .Errorf ("failed to check architecture: %w, stdout: %s, stderr: %s" , err , stdout , stderr )
94+ return "" , fmt .Errorf ("failed to check architecture: %w, stdout: %s, stderr: %s" , err , stdout , stderr )
6995 }
70- if ! strings .Contains (strings .TrimSpace (stdout ), "x86_64" ) {
71- return fmt .Errorf ("expected x86_64 architecture, got: %s" , strings .TrimSpace (stdout ))
96+ arch := strings .TrimSpace (stdout )
97+ if ! strings .Contains (arch , "x86_64" ) {
98+ return "" , fmt .Errorf ("expected x86_64 architecture, got: %s" , arch )
7299 }
100+ return "x86_64" , nil
101+ }
73102
74- // Check 2: Verify Ubuntu 20.04 or 22.04
75- stdout , stderr , err = sshClient .RunCommand (ctx , "cat /etc/os-release | grep PRETTY_NAME" )
103+ func validateOSVersion ( ctx context. Context , sshClient * ssh. Client ) ( string , error ) {
104+ stdout , stderr , err : = sshClient .RunCommand (ctx , "cat /etc/os-release | grep PRETTY_NAME" )
76105 if err != nil {
77- return fmt .Errorf ("failed to check OS version: %w, stdout: %s, stderr: %s" , err , stdout , stderr )
106+ return "" , fmt .Errorf ("failed to check OS version: %w, stdout: %s, stderr: %s" , err , stdout , stderr )
78107 }
79108
80109 parts := strings .Split (strings .TrimSpace (stdout ), "=" )
81110 if len (parts ) != 2 {
82- return fmt .Errorf ("error: os pretty name not in format PRETTY_NAME=\" Ubuntu\" : %s" , stdout )
111+ return "" , fmt .Errorf ("error: os pretty name not in format PRETTY_NAME=\" Ubuntu\" : %s" , stdout )
83112 }
84113
85- // Remove quotes from the value
86114 osVersion := strings .Trim (parts [1 ], "\" " )
87115 ubuntuRegex := regexp .MustCompile (`Ubuntu 20\.04|22\.04` )
88116 if ! ubuntuRegex .MatchString (osVersion ) {
89- return fmt .Errorf ("expected Ubuntu 20.04 or 22.04, got: %s" , osVersion )
117+ return "" , fmt .Errorf ("expected Ubuntu 20.04 or 22.04, got: %s" , osVersion )
90118 }
119+ return osVersion , nil
120+ }
91121
92- // Check 3: Verify home directory
93- stdout , stderr , err = sshClient .RunCommand (ctx , "cd ~ && pwd" )
122+ func validateHomeDirectory ( ctx context. Context , sshClient * ssh. Client , sshUser string ) ( string , error ) {
123+ stdout , stderr , err : = sshClient .RunCommand (ctx , "cd ~ && pwd" )
94124 if err != nil {
95- return fmt .Errorf ("failed to check home directory: %w, stdout: %s, stderr: %s" , err , stdout , stderr )
125+ return "" , fmt .Errorf ("failed to check home directory: %w, stdout: %s, stderr: %s" , err , stdout , stderr )
96126 }
97127
98128 homeDir := strings .TrimSpace (stdout )
99129 if sshUser == "ubuntu" {
100130 if ! strings .Contains (homeDir , "/home/ubuntu" ) {
101- return fmt .Errorf ("expected ubuntu user home directory to contain /home/ubuntu, got: %s" , homeDir )
131+ return "" , fmt .Errorf ("expected ubuntu user home directory to contain /home/ubuntu, got: %s" , homeDir )
102132 }
103133 } else {
104134 if ! strings .Contains (homeDir , "/root" ) {
105- return fmt .Errorf ("expected non-ubuntu user home directory to contain /root, got: %s" , homeDir )
135+ return "" , fmt .Errorf ("expected non-ubuntu user home directory to contain /root, got: %s" , homeDir )
106136 }
107137 }
138+ return homeDir , nil
139+ }
108140
109- fmt . Printf ( "Instance image validation passed for %s: architecture=%s, os=%s, home=%s \n " ,
110- instance . CloudID , "x86_64" , osVersion , homeDir )
141+ func validateSystemd ( ctx context. Context , sshClient * ssh. Client ) ( string , error ) {
142+ stdout , stderr , err := sshClient . RunCommand ( ctx , "systemctl is-system-running" )
111143
112- return nil
144+ systemdStatus := strings .TrimSpace (stdout )
145+ if systemdStatus == "running" || systemdStatus == "degraded" {
146+ return systemdStatus , nil
147+ }
148+
149+ if err != nil {
150+ return "" , fmt .Errorf ("failed to check systemd status: %w, stdout: %s, stderr: %s" , err , stdout , stderr )
151+ }
152+
153+ return "" , fmt .Errorf ("expected systemd to be running or degraded, got: %s" , systemdStatus )
113154}
0 commit comments