From 85dae108214f06b332f3071402f15a4da1bd5eb9 Mon Sep 17 00:00:00 2001 From: Neo Liang Date: Fri, 16 Oct 2020 20:16:58 +0800 Subject: [PATCH] gardenctl ssh for openstack node --- pkg/cmd/openstack.go | 4 +- pkg/cmd/operate.go | 12 +++-- pkg/cmd/ssh.go | 1 + pkg/cmd/ssh_openstack.go | 103 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 pkg/cmd/ssh_openstack.go diff --git a/pkg/cmd/openstack.go b/pkg/cmd/openstack.go index 0f83ac18c..141ad3a9f 100644 --- a/pkg/cmd/openstack.go +++ b/pkg/cmd/openstack.go @@ -37,8 +37,8 @@ func NewOpenstackCmd(targetReader TargetReader) *cobra.Command { fmt.Println("Please go to https://docs.openstack.org/newton/user-guide/common/cli-install-openstack-command-line-clients.html for how to install openstack cli") os.Exit(2) } - arguments := "openstack " + strings.Join(args[:], " ") - operate("openstack", arguments) + arguments := strings.Join(args[:], " ") + fmt.Println(operate("openstack", arguments)) return nil }, diff --git a/pkg/cmd/operate.go b/pkg/cmd/operate.go index af24d0b55..88caa4edc 100644 --- a/pkg/cmd/operate.go +++ b/pkg/cmd/operate.go @@ -186,11 +186,17 @@ func operate(provider, arguments string) string { password := []byte(secret.Data["password"]) tenantName := []byte(secret.Data["tenantName"]) username := []byte(secret.Data["username"]) - err = ExecCmd(nil, arguments, false, "OS_IDENTITY_API_VERSION=3", "OS_AUTH_VERSION=3", "OS_AUTH_STRATEGY=keystone", "OS_AUTH_URL="+authURL, "OS_TENANT_NAME="+string(tenantName[:]), - "OS_PROJECT_DOMAIN_NAME="+string(domainName[:]), "OS_USER_DOMAIN_NAME="+string(domainName[:]), "OS_USERNAME="+string(username[:]), "OS_PASSWORD="+string(password[:]), "OS_REGION_NAME="+region) + + args := strings.Fields(arguments) + cmd := exec.Command("openstack", args...) + newEnv := append(os.Environ(), "OS_IDENTITY_API_VERSION=3", "OS_AUTH_VERSION=3", "OS_AUTH_STRATEGY=keystone", "OS_AUTH_URL="+authURL, "OS_TENANT_NAME="+string(tenantName[:]), "OS_PROJECT_DOMAIN_NAME="+string(domainName[:]), "OS_USER_DOMAIN_NAME="+string(domainName[:]), "OS_USERNAME="+string(username[:]), "OS_PASSWORD="+string(password[:]), "OS_REGION_NAME="+region) + cmd.Env = newEnv + out, err = cmd.CombinedOutput() if err != nil { - os.Exit(2) + fmt.Println(err) + log.Fatalf("Openstack CLI failed with %s\n%s\n", out, err) } + case "aliyun": accessKeyID := []byte(secret.Data["accessKeyID"]) accessKeySecret := []byte(secret.Data["accessKeySecret"]) diff --git a/pkg/cmd/ssh.go b/pkg/cmd/ssh.go index bc324cf60..e0862e7da 100644 --- a/pkg/cmd/ssh.go +++ b/pkg/cmd/ssh.go @@ -97,6 +97,7 @@ func NewSSHCmd(reader TargetReader, ioStreams IOStreams) *cobra.Command { case "alicloud": sshToAlicloudNode(args[0], path, user, pathSSKeypair, sshPublicKey, myPublicIP) case "openstack": + sshToOpenstackNode(args[0], path, user, pathSSKeypair, sshPublicKey, myPublicIP) default: return fmt.Errorf("infrastructure type %q not found", infraType) } diff --git a/pkg/cmd/ssh_openstack.go b/pkg/cmd/ssh_openstack.go new file mode 100644 index 000000000..4a12d9a7f --- /dev/null +++ b/pkg/cmd/ssh_openstack.go @@ -0,0 +1,103 @@ +// Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SSH to openstack is performed in following steps: +// 1) get network ID of public network +// 2) create floating IP from public network +// 3) associate server node with FIP created +// 4) perform ssh +// 5) perform cleanup (de-associate FIP from server / delete FIP) +// Note: no Bastion VM is needed, no SG rule is needed +// + +package cmd + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "time" +) + +//OpenstackInstanceAttribute stores all the critical information for creating an instance on Openstack. +type OpenstackInstanceAttribute struct { + InstanceID string + networkID string + FIP string +} + +//sshToOpenstackNode ssh to openstack node +func sshToOpenstackNode(nodeName, path, user, pathSSKeypair string, sshPublicKey []byte, myPublicIP string) { + a := &OpenstackInstanceAttribute{} + a.InstanceID = nodeName + var err error + + fmt.Println("(1/5) Getting the external network for creating FIP") + resNetwork := operate("openstack", "network list --external -f json") + if len(resNetwork) < 2 { + fmt.Println("External network not found!") + os.Exit(2) + } + resNetwork = resNetwork[1 : len(resNetwork)-2] // network returns with [], trim them before next step json decode + decodedQueryNetwork := decodeAndQueryFromJSONString(resNetwork) + a.networkID, err = decodedQueryNetwork.String("ID") + fmt.Println("The external network ID is " + a.networkID) + checkError(err) + + fmt.Println("(2/5) Creating floating IP from external network") + resFloatingIP := operate("openstack", "floating ip create "+a.networkID+" -f json") + decodedQueryFIP := decodeAndQueryFromJSONString(resFloatingIP) + a.FIP, err = decodedQueryFIP.String("floating_ip_address") + fmt.Println("The floating IP created is " + a.FIP) + checkError(err) + time.Sleep(5000) + + fmt.Println("(3/5) Add floating IP to openstack server node") + operate("openstack", "server add floating ip "+a.InstanceID+" "+a.FIP) + time.Sleep(5000) + + defer a.cleanUpOpenstack() + + node := user + "@" + a.FIP + fmt.Println("(4/5) Establishing SSH connection") + fmt.Println("") + + key := filepath.Join(pathSSKeypair, "key") + args := []string{"-i" + key, "-oStrictHostKeyChecking=no", node} + if debugSwitch { + args = append([]string{"-vvv"}, args...) + } + + cmd := exec.Command("ssh", args...) + cmd.Stdout = os.Stdout + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Println(err) + } +} + +//cleanUpOpenstack clean the resource added to ssh to openstack node +func (a *OpenstackInstanceAttribute) cleanUpOpenstack() { + fmt.Println("") + fmt.Println("(5/5) Cleanup") + + fmt.Println("De-associate server with floating ip") + operate("openstack", "server remove floating ip "+a.InstanceID+" "+a.FIP) + + fmt.Println("Delete the floating IP") + operate("openstack", "floating ip delete "+a.FIP) + +}