Skip to content

Commit 157a515

Browse files
Mia-Crossbene2k1
andauthored
feat(instance): add fetch-keys to ssh commands (#4622)
Co-authored-by: Benedikt Rollik <brollik@scaleway.com>
1 parent 2fd0824 commit 157a515

File tree

6 files changed

+153
-3
lines changed

6 files changed

+153
-3
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
2+
🟥🟥🟥 STDERR️️ 🟥🟥🟥️
3+
Keys registered via the Scaleway Console will be propagated to the selected servers.
4+
The command 'ssh <server-ip> -t -l <username> scw-fetch-ssh-keys --upgrade' will be run on the servers matching the zone and project filters.
5+
Keep in mind that you need to be able to connect to your server with another key than the one you want to add.
6+
Keep in mind that SSH keys are scoped by project.
7+
8+
USAGE:
9+
scw instance ssh fetch-keys [arg=value ...]
10+
11+
ARGS:
12+
[project-id] Fetch the keys on all servers in the given Project
13+
[username=root] Username used for the SSH connection
14+
[zone=fr-par-1] Zone to target. If none is passed will use default zone from the config (fr-par-1 | fr-par-2 | fr-par-3 | nl-ams-1 | nl-ams-2 | nl-ams-3 | pl-waw-1 | pl-waw-2 | pl-waw-3)
15+
16+
FLAGS:
17+
-h, --help help for fetch-keys
18+
19+
GLOBAL FLAGS:
20+
-c, --config string The path to the config file
21+
-D, --debug Enable debug mode
22+
-o, --output string Output format: json or human, see 'scw help output' for more info (default "human")
23+
-p, --profile string The config profile to use
24+
--web open console page for the current ressource

cmd/scw/testdata/test-all-usage-instance-ssh-list-keys-usage.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ USAGE:
88
scw instance ssh list-keys <server-id ...> [arg=value ...]
99

1010
ARGS:
11-
server-id Server to add your key to
11+
server-id Server which keys are to be listed
1212
[zone=fr-par-1] Zone to target. If none is passed will use default zone from the config (fr-par-1 | fr-par-2 | fr-par-3 | nl-ams-1 | nl-ams-2 | nl-ams-3 | pl-waw-1 | pl-waw-2 | pl-waw-3)
1313

1414
FLAGS:

cmd/scw/testdata/test-all-usage-instance-ssh-usage.golden

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ USAGE:
99

1010
UTILITY COMMANDS:
1111
add-key Add a public key to a server
12+
fetch-keys Fetch SSH keys from the console and install them on multiple servers
1213
list-keys List manually added public keys
1314
remove-key Remove a manually added public key from a server
1415

docs/commands/instance.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ This API allows you to manage your Instances.
8787
- [Wait for snapshot to reach a stable state](#wait-for-snapshot-to-reach-a-stable-state)
8888
- [SSH Utilities](#ssh-utilities)
8989
- [Add a public key to a server](#add-a-public-key-to-a-server)
90+
- [Fetch SSH keys from the console and install them on multiple servers](#fetch-ssh-keys-from-the-console-and-install-them-on-multiple-servers)
9091
- [Install a ssh config with all your servers as host
9192
It generate hosts for instance servers, baremetal, apple-silicon and bastions](#install-a-ssh-config-with-all-your-servers-as-host
9293
it-generate-hosts-for-instance-servers,-baremetal,-apple-silicon-and-bastions)
@@ -2769,6 +2770,30 @@ scw instance ssh add-key [arg=value ...]
27692770

27702771

27712772

2773+
### Fetch SSH keys from the console and install them on multiple servers
2774+
2775+
Keys registered via the Scaleway Console will be propagated to the selected servers.
2776+
The command 'ssh <server-ip> -t -l <username> scw-fetch-ssh-keys --upgrade' will be run on the servers matching the zone and project filters.
2777+
Keep in mind that you need to be able to connect to your server with another key than the one you want to add.
2778+
Keep in mind that SSH keys are scoped by project.
2779+
2780+
**Usage:**
2781+
2782+
```
2783+
scw instance ssh fetch-keys [arg=value ...]
2784+
```
2785+
2786+
2787+
**Args:**
2788+
2789+
| Name | | Description |
2790+
|------|---|-------------|
2791+
| project-id | | Fetch the keys on all servers in the given Project |
2792+
| username | Default: `root` | Username used for the SSH connection |
2793+
| zone | Default: `fr-par-1`<br />One of: `fr-par-1`, `fr-par-2`, `fr-par-3`, `nl-ams-1`, `nl-ams-2`, `nl-ams-3`, `pl-waw-1`, `pl-waw-2`, `pl-waw-3` | Zone to target. If none is passed will use default zone from the config |
2794+
2795+
2796+
27722797
### Install a ssh config with all your servers as host
27732798
It generate hosts for instance servers, baremetal, apple-silicon and bastions
27742799

@@ -2807,7 +2832,7 @@ scw instance ssh list-keys <server-id ...> [arg=value ...]
28072832

28082833
| Name | | Description |
28092834
|------|---|-------------|
2810-
| server-id | Required | Server to add your key to |
2835+
| server-id | Required | Server which keys are to be listed |
28112836
| zone | Default: `fr-par-1`<br />One of: `fr-par-1`, `fr-par-2`, `fr-par-3`, `nl-ams-1`, `nl-ams-2`, `nl-ams-3`, `pl-waw-1`, `pl-waw-2`, `pl-waw-3` | Zone to target. If none is passed will use default zone from the config |
28122837

28132838

internal/namespaces/instance/v1/custom.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ func GetCommands() *core.Commands {
197197
instanceSSH(),
198198
sshAddKeyCommand(),
199199
sshConfigInstallCommand(),
200+
sshFetchKeysCommand(),
200201
sshListKeysCommand(),
201202
sshRemoveKeyCommand(),
202203
instanceServerGetRdpPassword(),

internal/namespaces/instance/v1/custom_ssh_key.go

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import (
77
"errors"
88
"fmt"
99
"hash/crc32"
10+
"os/exec"
1011
"reflect"
1112
"strings"
1213

1314
"github.com/scaleway/scaleway-cli/v2/core"
1415
"github.com/scaleway/scaleway-cli/v2/core/human"
16+
"github.com/scaleway/scaleway-cli/v2/internal/interactive"
1517
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
1618
"github.com/scaleway/scaleway-sdk-go/scw"
1719
)
@@ -132,6 +134,103 @@ Lookup /root/.ssh/authorized_keys on your server for more information`,
132134
}
133135
}
134136

137+
type sshFetchKeysRequest struct {
138+
Zone scw.Zone
139+
ProjectID string
140+
Username string
141+
}
142+
143+
func sshFetchKeysCommand() *core.Command {
144+
return &core.Command{
145+
Namespace: "instance",
146+
Resource: "ssh",
147+
Verb: "fetch-keys",
148+
Groups: []string{"utility"},
149+
Short: "Fetch SSH keys from the console and install them on multiple servers",
150+
Long: `Keys registered via the Scaleway Console will be propagated to the selected servers.
151+
The command 'ssh <server-ip> -t -l <username> scw-fetch-ssh-keys --upgrade' will be run on the servers matching the zone and project filters.
152+
Keep in mind that you need to be able to connect to your server with another key than the one you want to add.
153+
Keep in mind that SSH keys are scoped by project.`,
154+
ArgsType: reflect.TypeOf(sshFetchKeysRequest{}),
155+
ArgSpecs: core.ArgSpecs{
156+
{
157+
Name: "project-id",
158+
Short: "Fetch the keys on all servers in the given Project",
159+
Required: false,
160+
},
161+
{
162+
Name: "username",
163+
Short: "Username used for the SSH connection",
164+
Default: core.DefaultValueSetter("root"),
165+
},
166+
core.ZoneArgSpec(((*instance.API)(nil)).Zones()...),
167+
},
168+
Run: func(ctx context.Context, argsI interface{}) (interface{}, error) {
169+
args := argsI.(*sshFetchKeysRequest)
170+
api := instance.NewAPI(core.ExtractClient(ctx))
171+
172+
listServersRequest := &instance.ListServersRequest{
173+
Zone: args.Zone,
174+
}
175+
if args.ProjectID != "" {
176+
listServersRequest.Project = &args.ProjectID
177+
}
178+
servers, err := api.ListServers(listServersRequest, scw.WithAllPages(), scw.WithContext(ctx))
179+
if err != nil {
180+
return nil, fmt.Errorf("failed to fetch servers: %w", err)
181+
}
182+
183+
for i, server := range servers.Servers {
184+
msg := fmt.Sprintf("Loading SSH keys on server %q", server.Name)
185+
if i == 0 {
186+
_, _ = interactive.Println(">", msg)
187+
} else {
188+
_, _ = interactive.Println("\n>", msg)
189+
}
190+
191+
if server.State != instance.ServerStateRunning {
192+
_, _ = interactive.Printf("Failed: server %q is not running", server.Name)
193+
194+
continue
195+
}
196+
197+
if len(server.PublicIPs) == 0 {
198+
_, _ = interactive.Printf("Failed: server %q has no public IP", server.Name)
199+
200+
continue
201+
}
202+
203+
for _, publicIP := range server.PublicIPs {
204+
sshArgs := []string{
205+
publicIP.Address.String(),
206+
"-t",
207+
"-l", args.Username,
208+
"/usr/sbin/scw-fetch-ssh-keys",
209+
"--upgrade",
210+
}
211+
212+
sshCmd := exec.Command("ssh", sshArgs...)
213+
214+
_, _ = interactive.Println(sshCmd)
215+
216+
exitCode, err := core.ExecCmd(ctx, sshCmd)
217+
if err != nil || exitCode != 0 {
218+
if err != nil {
219+
_, _ = interactive.Println("Failed:", err)
220+
} else {
221+
_, _ = interactive.Println("Failed: ssh command failed with exit code", exitCode)
222+
}
223+
} else {
224+
_, _ = interactive.Println("Success")
225+
}
226+
}
227+
}
228+
229+
return &core.SuccessResult{Empty: true}, nil
230+
},
231+
}
232+
}
233+
135234
type sshListKeysRequest struct {
136235
Zone scw.Zone
137236
ServerID string
@@ -151,7 +250,7 @@ Lookup /root/.ssh/authorized_keys on your server for more information`,
151250
ArgSpecs: core.ArgSpecs{
152251
{
153252
Name: "server-id",
154-
Short: "Server to add your key to",
253+
Short: "Server which keys are to be listed",
155254
Positional: true,
156255
Required: true,
157256
},

0 commit comments

Comments
 (0)