Skip to content

Commit f88ef9a

Browse files
authored
Add subcommand to create a new nanohub instance (#19)
1 parent a51a7d5 commit f88ef9a

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

internal/cli/new.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package cli
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"os"
10+
"path/filepath"
11+
"time"
12+
13+
"github.com/spf13/cobra"
14+
)
15+
16+
type ProvisioningResponse struct {
17+
Name string `json:"name"`
18+
EnrollmentProfile string `json:"enrollment_profile"`
19+
APIKey string `json:"api_key"`
20+
}
21+
22+
func newCmd() *cobra.Command {
23+
newCmd := &cobra.Command{
24+
Use: "new",
25+
Short: "Create a new nanohub instance",
26+
Long: "Create a new nanohub instance with the provided token",
27+
RunE: newCmdFn,
28+
}
29+
30+
newCmd.Flags().StringP("token", "t", "", "Token for authentication")
31+
newCmd.MarkFlagRequired("token")
32+
33+
return newCmd
34+
}
35+
36+
func newCmdFn(cmd *cobra.Command, args []string) error {
37+
// Get home directory and create config path
38+
homeDir, err := os.UserHomeDir()
39+
if err != nil {
40+
return fmt.Errorf("failed to get home directory: %v", err)
41+
}
42+
43+
configDir := filepath.Join(homeDir, ".nanohubctl")
44+
configFile := filepath.Join(configDir, "config.json")
45+
46+
// Check if config file already exists
47+
if _, err := os.Stat(configFile); err == nil {
48+
// Config exists, read and display it
49+
data, err := os.ReadFile(configFile)
50+
if err != nil {
51+
return fmt.Errorf("failed to read existing config: %v", err)
52+
}
53+
54+
var existingResp ProvisioningResponse
55+
if err := json.Unmarshal(data, &existingResp); err != nil {
56+
return fmt.Errorf("failed to parse existing config: %v", err)
57+
}
58+
59+
fmt.Printf("You already have a nanohub instance configured:\n\n")
60+
printInstanceInfo(existingResp)
61+
return nil
62+
}
63+
64+
// Config doesn't exist, proceed with creating new instance
65+
token, err := cmd.Flags().GetString("token")
66+
if err != nil {
67+
return err
68+
}
69+
70+
client := &http.Client{
71+
Timeout: 60 * time.Second, // Set timeout to 60 seconds since it can take > 30s
72+
}
73+
74+
req, err := http.NewRequest("POST", "https://provisioning.macadmins.io/new", nil)
75+
if err != nil {
76+
return err
77+
}
78+
79+
// Set basic auth header
80+
username := "nanohub"
81+
auth := username + ":" + token
82+
encodedAuth := base64.StdEncoding.EncodeToString([]byte(auth))
83+
req.Header.Add("Authorization", "Basic "+encodedAuth)
84+
85+
resp, err := client.Do(req)
86+
if err != nil {
87+
return err
88+
}
89+
defer resp.Body.Close()
90+
91+
body, err := io.ReadAll(resp.Body)
92+
if err != nil {
93+
return err
94+
}
95+
96+
// Check if the response status is not successful
97+
if resp.StatusCode != http.StatusOK {
98+
return fmt.Errorf("server returned status %d: %s", resp.StatusCode, string(body))
99+
}
100+
101+
var provisioningResp ProvisioningResponse
102+
if err := json.Unmarshal(body, &provisioningResp); err != nil {
103+
return fmt.Errorf("failed to parse JSON response: %v\nResponse body: %s", err, string(body))
104+
}
105+
106+
// Create config directory if it doesn't exist
107+
if err := os.MkdirAll(configDir, 0755); err != nil {
108+
return fmt.Errorf("failed to create config directory: %v", err)
109+
}
110+
111+
// Save the response to config file
112+
configData, err := json.MarshalIndent(provisioningResp, "", " ")
113+
if err != nil {
114+
return fmt.Errorf("failed to marshal config data: %v", err)
115+
}
116+
117+
if err := os.WriteFile(configFile, configData, 0600); err != nil {
118+
return fmt.Errorf("failed to write config file: %v", err)
119+
}
120+
121+
// Print formatted output
122+
fmt.Printf("Successfully created new nanohub instance:\n\n")
123+
printInstanceInfo(provisioningResp)
124+
return nil
125+
}
126+
127+
func printInstanceInfo(resp ProvisioningResponse) {
128+
fmt.Printf("Instance Name: %s\n", resp.Name)
129+
fmt.Printf("API Key: %s\n", resp.APIKey)
130+
fmt.Printf("Enrollment Profile: %s\n", resp.EnrollmentProfile)
131+
fmt.Printf("\nTo configure nanohubctl, run:\n\n")
132+
fmt.Printf("export NANOHUB_URL=https://%s\n", resp.Name)
133+
fmt.Printf("export NANOHUB_API_KEY=%s\n", resp.APIKey)
134+
}

internal/cli/root.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var (
1818
debug bool
1919
vv bool
2020

21-
version string = "1.0.7"
21+
version string = "1.0.8"
2222
)
2323

2424
func setLoggerOpts() {
@@ -89,6 +89,7 @@ func rootCmd() *cobra.Command {
8989
ddm.RootCmd(),
9090
nanocmd.RootCmd(),
9191
godeclr.RootCmd(),
92+
newCmd(),
9293
)
9394

9495
return rootCmd

0 commit comments

Comments
 (0)