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  }