yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/openstack/keypaire.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 openstack 16 17 import ( 18 "fmt" 19 "net/url" 20 21 "yunion.io/x/pkg/errors" 22 23 "yunion.io/x/cloudmux/pkg/cloudprovider" 24 "yunion.io/x/onecloud/pkg/util/rand" 25 ) 26 27 type SKeypair struct { 28 Fingerprint string 29 Name string 30 Type string 31 PublicKey string 32 } 33 34 type SKeyPair struct { 35 Keypair SKeypair 36 } 37 38 func (region *SRegion) GetKeypairs() ([]SKeyPair, error) { 39 keypairs := []SKeyPair{} 40 resource := "/os-keypairs" 41 query := url.Values{} 42 for { 43 resp, err := region.ecsList(resource, query) 44 if err != nil { 45 return nil, errors.Wrap(err, "ecsList") 46 } 47 part := struct { 48 Keypairs []SKeyPair 49 KeypairsLinks SNextLinks 50 }{} 51 err = resp.Unmarshal(&part) 52 if err != nil { 53 return nil, errors.Wrap(err, "resp.Unmarshal") 54 } 55 keypairs = append(keypairs, part.Keypairs...) 56 marker := part.KeypairsLinks.GetNextMark() 57 if len(marker) == 0 { 58 break 59 } 60 query.Set("marker", marker) 61 } 62 return keypairs, nil 63 } 64 65 func (region *SRegion) CreateKeypair(name, publicKey, Type string) (*SKeyPair, error) { 66 params := map[string]map[string]string{ 67 "keypair": { 68 "name": name, 69 "public_key": publicKey, 70 }, 71 } 72 if len(Type) > 0 { 73 params["keypair"]["type"] = Type 74 } 75 resp, err := region.ecsPost("/os-keypairs", params) 76 if err != nil { 77 return nil, errors.Wrap(err, "ecsPost") 78 } 79 keypair := &SKeyPair{} 80 err = resp.Unmarshal(keypair) 81 if err != nil { 82 return nil, errors.Wrap(err, "resp.Unmarshal") 83 } 84 return keypair, nil 85 } 86 87 func (region *SRegion) DeleteKeypair(name string) error { 88 _, err := region.ecsDelete("/os-keypairs/" + name) 89 return err 90 } 91 92 func (region *SRegion) GetKeypair(name string) (*SKeyPair, error) { 93 resp, err := region.ecsGet("/os-keypairs/" + name) 94 if err != nil { 95 return nil, errors.Wrap(err, "ecsGet") 96 } 97 keypair := &SKeyPair{} 98 err = resp.Unmarshal(keypair) 99 if err != nil { 100 return nil, errors.Wrap(err, "resp.Unmarshal") 101 } 102 return keypair, nil 103 } 104 105 func (region *SRegion) syncKeypair(namePrefix, publicKey string) (string, error) { 106 keypairs, err := region.GetKeypairs() 107 if err != nil { 108 return "", err 109 } 110 111 for _, keypair := range keypairs { 112 if keypair.Keypair.PublicKey == publicKey { 113 return keypair.Keypair.Name, nil 114 } 115 } 116 randomString := func(prefix string, length int) string { 117 return fmt.Sprintf("%s-%s", prefix, rand.String(length)) 118 } 119 for i := 1; i < 10; i++ { 120 name := randomString(namePrefix, i) 121 if _, err := region.GetKeypair(name); err != nil { 122 if errors.Cause(err) == cloudprovider.ErrNotFound { 123 keypair, err := region.CreateKeypair(name, publicKey, "ssh") 124 if err != nil { 125 return "", errors.Wrapf(err, "CreateKeypair") 126 } 127 return keypair.Keypair.Name, nil 128 } 129 } 130 } 131 return "", fmt.Errorf("failed to find uniq name for keypair") 132 }