11package cmd
22
33import (
4+ "bytes"
45 "context"
56 "encoding/base64"
67 "fmt"
8+ "github.com/loft-sh/log"
9+ "github.com/pkg/errors"
10+ "gopkg.in/yaml.v3"
11+ "net"
12+ "time"
713
814 "github.com/loft-sh/devpod/pkg/ssh"
915 "github.com/spf13/cobra"
@@ -12,6 +18,44 @@ import (
1218 "github.com/stackitcloud/devpod-provider-stackit/pkg/stackit"
1319)
1420
21+ const maxConnectionAttempts = 42
22+
23+ type cloudInit struct {
24+ Status string `json:"status"`
25+ }
26+
27+ func checkConnectionStatus (ctx context.Context , publicIP string , privateKey * []byte ) bool {
28+ // Call external address
29+ sshClient , err := ssh .NewSSHClient (stackit .SSHUserName , net .JoinHostPort (publicIP , stackit .SSHPort ), * privateKey )
30+ if err != nil {
31+ log .Default .Debugf ("Error creating ssh client: %v" , err )
32+ return false
33+ }
34+ defer func () {
35+ if err := sshClient .Close (); err != nil {
36+ log .Default .Debugf ("Error closing ssh client: %v" , err )
37+ }
38+ }()
39+
40+ buf := new (bytes.Buffer )
41+ if err := ssh .Run (ctx , sshClient , "cloud-init status || true" , & bytes.Buffer {}, buf , & bytes.Buffer {}, nil ); err != nil {
42+ log .Default .Errorf ("Error retrieving cloud-init status, %v" , err )
43+ return false
44+ }
45+
46+ var status cloudInit
47+ if err := yaml .Unmarshal (buf .Bytes (), & status ); err != nil {
48+ log .Default .Errorf ("Unable to parse cloud-init YAML: %v" , err )
49+ return false
50+ }
51+
52+ if status .Status != "done" {
53+ return false
54+ }
55+
56+ return true
57+ }
58+
1559// createCmd represents the create command.
1660var createCmd = & cobra.Command {
1761 Use : "create" ,
@@ -35,7 +79,39 @@ var createCmd = &cobra.Command{
3579 return fmt .Errorf ("can't b64decode public key: %w" , err )
3680 }
3781
38- return s .Create (ctx , options , publicKey )
82+ if err := s .Create (ctx , options , publicKey ); err != nil {
83+ return err
84+ }
85+
86+ privateKey , err := ssh .GetPrivateKeyRawBase (options .MachineFolder )
87+ if err != nil {
88+ return errors .Wrap (err , "load private key" )
89+ }
90+
91+ publicIP , err := stackit .New (options .ClientOptions ).GetPublicIPOfServer (ctx , options .ProjectID , options .MachineID )
92+ if err != nil {
93+ return errors .Wrap (err , "get public IP" )
94+ }
95+
96+ attempt := 0
97+
98+ for {
99+ if attempt >= maxConnectionAttempts {
100+ return errors .New ("max connection attempts reached" )
101+ }
102+ attempt ++
103+
104+ log .Default .Debugf ("Attempt %d of %d to connect to server using ssh" , attempt , maxConnectionAttempts )
105+
106+ time .Sleep (time .Second )
107+
108+ if checkConnectionStatus (ctx , publicIP , & privateKey ) {
109+ log .Default .Info ("Successfully connected to server" )
110+ break
111+ }
112+ }
113+
114+ return nil
39115 },
40116}
41117
0 commit comments