yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ctyun/keypair.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ctyun 16 17 import ( 18 "fmt" 19 "strconv" 20 "time" 21 22 "github.com/aokoli/goutils" 23 "golang.org/x/crypto/ssh" 24 25 "yunion.io/x/jsonutils" 26 "yunion.io/x/pkg/errors" 27 ) 28 29 // GET http://ctyun-api-url/apiproxy/v3/querySSH 30 // POST http://ctyun-api-url/apiproxy/v3/deleteSSH 31 type SKeypair struct { 32 Fingerprint string `json:"fingerprint"` 33 Name string `json:"name"` 34 PublicKey string `json:"public_key"` 35 } 36 37 func (self *SRegion) getFingerprint(publicKey string) (string, error) { 38 pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey)) 39 if err != nil { 40 return "", fmt.Errorf("publicKey error %s", err) 41 } 42 43 return ssh.FingerprintSHA256(pk), nil 44 } 45 46 // GET http://ctyun-api-url/apiproxy/v3/querySSH 47 func (self *SRegion) GetKeypairs() ([]SKeypair, int, error) { 48 params := map[string]string{ 49 "regionId": self.GetId(), 50 } 51 52 resp, err := self.client.DoGet("/apiproxy/v3/querySSH", params) 53 if err != nil { 54 return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs.DoGet") 55 } 56 57 keypairs := []jsonutils.JSONObject{} 58 err = resp.Unmarshal(&keypairs, "returnObj", "keypairs") 59 if err != nil { 60 return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs.Unmarshal") 61 } 62 63 ret := []SKeypair{} 64 for i := range keypairs { 65 k, err := keypairs[i].Get("keypair") 66 if err != nil { 67 return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs") 68 } 69 70 keypair := SKeypair{} 71 err = k.Unmarshal(&keypair) 72 if err != nil { 73 return nil, 0, errors.Wrap(err, "SRegion.GetKeypairs.Unmarshal") 74 } 75 76 ret = append(ret, keypair) 77 } 78 79 return ret, len(ret), nil 80 } 81 82 func (self *SRegion) GetKeypair(name string) (*SKeypair, error) { 83 keypairs, _, err := self.GetKeypairs() 84 if err != nil { 85 return nil, errors.Wrap(err, "SRegion.GetKeypair.GetKeypairs") 86 } 87 88 for i := range keypairs { 89 if keypairs[i].Name == name { 90 return &keypairs[i], nil 91 } 92 } 93 94 return nil, errors.Wrap(errors.ErrNotFound, "SRegion.GetKeypair") 95 } 96 97 func (self *SRegion) lookUpKeypair(publicKey string) (string, error) { 98 keypairs, _, err := self.GetKeypairs() 99 if err != nil { 100 return "", err 101 } 102 103 fingerprint, err := self.getFingerprint(publicKey) 104 if err != nil { 105 return "", err 106 } 107 108 for _, keypair := range keypairs { 109 if keypair.Fingerprint == fingerprint { 110 return keypair.Name, nil 111 } 112 } 113 114 return "", fmt.Errorf("keypair not found %s", err) 115 } 116 117 // POST http://ctyun-api-url/apiproxy/v3/createSSH 118 func (self *SRegion) ImportKeypair(name, publicKey string) (*SKeypair, error) { 119 params := map[string]jsonutils.JSONObject{ 120 "regionId": jsonutils.NewString(self.GetId()), 121 "name": jsonutils.NewString(name), 122 "publicKey": jsonutils.NewString(publicKey), 123 } 124 125 _, err := self.client.DoPost("/apiproxy/v3/createSSH", params) 126 if err != nil { 127 return nil, errors.Wrap(err, "SRegion.ImportKeypair.DoPost") 128 } 129 130 return self.GetKeypair(name) 131 } 132 133 func (self *SRegion) importKeypair(publicKey string) (string, error) { 134 prefix, e := goutils.RandomAlphabetic(6) 135 if e != nil { 136 return "", fmt.Errorf("publicKey error %s", e) 137 } 138 139 name := prefix + strconv.FormatInt(time.Now().Unix(), 10) 140 if k, e := self.ImportKeypair(name, publicKey); e != nil { 141 return "", fmt.Errorf("keypair import error %s", e) 142 } else { 143 return k.Name, nil 144 } 145 } 146 147 func (self *SRegion) syncKeypair(publicKey string) (string, error) { 148 name, e := self.lookUpKeypair(publicKey) 149 if e == nil { 150 return name, nil 151 } 152 return self.importKeypair(publicKey) 153 }