keypair.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. package qcloud
  15. import (
  16. "fmt"
  17. "strconv"
  18. "time"
  19. "github.com/aokoli/goutils"
  20. "golang.org/x/crypto/ssh"
  21. "yunion.io/x/log"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. )
  24. type SKeypair struct {
  25. AssociatedInstanceIds []string
  26. CreateTime time.Time
  27. Description string
  28. KeyId string
  29. KeyName string
  30. PublicKey string
  31. }
  32. func (self *SRegion) GetKeypairs(name string, keyIds []string, offset int, limit int) ([]SKeypair, int, error) {
  33. if limit > 50 || limit <= 0 {
  34. limit = 50
  35. }
  36. params := map[string]string{}
  37. params["Limit"] = fmt.Sprintf("%d", limit)
  38. params["Offset"] = fmt.Sprintf("%d", offset)
  39. if len(keyIds) > 0 {
  40. for i := 0; i < len(keyIds); i++ {
  41. params[fmt.Sprintf("KeyIds.%d", i)] = keyIds[i]
  42. }
  43. } else {
  44. if len(name) > 0 {
  45. params["Filters.0.Name"] = "key-name"
  46. params["Filters.0.Values.0"] = name
  47. }
  48. }
  49. body, err := self.cvmRequest("DescribeKeyPairs", params, true)
  50. if err != nil {
  51. log.Errorf("GetKeypairs fail %s", err)
  52. return nil, 0, err
  53. }
  54. keypairs := []SKeypair{}
  55. err = body.Unmarshal(&keypairs, "KeyPairSet")
  56. if err != nil {
  57. log.Errorf("Unmarshal keypair fail %s", err)
  58. return nil, 0, err
  59. }
  60. total, _ := body.Float("TotalCount")
  61. return keypairs, int(total), nil
  62. }
  63. func (self *SRegion) ImportKeypair(name string, pubKey string) (*SKeypair, error) {
  64. params := map[string]string{}
  65. params["PublicKey"] = pubKey
  66. params["ProjectId"] = "0"
  67. params["KeyName"] = name
  68. body, err := self.cvmRequest("ImportKeyPair", params, true)
  69. if err != nil {
  70. log.Errorf("ImportKeypair fail %s", err)
  71. return nil, err
  72. }
  73. keypairID, err := body.GetString("KeyId")
  74. if err != nil {
  75. return nil, err
  76. }
  77. keypairs, total, err := self.GetKeypairs("", []string{keypairID}, 0, 1)
  78. if err != nil {
  79. return nil, err
  80. }
  81. if total != 1 {
  82. return nil, cloudprovider.ErrNotFound
  83. }
  84. return &keypairs[0], nil
  85. }
  86. func (self *SRegion) AttachKeypair(instanceId string, keypairId string) error {
  87. params := map[string]string{}
  88. params["InstanceIds.0"] = instanceId
  89. params["KeyIds.0"] = keypairId
  90. _, err := self.cvmRequest("AssociateInstancesKeyPairs", params, true)
  91. return err
  92. }
  93. func (self *SRegion) DetachKeyPair(instanceId string, keypairId string) error {
  94. params := make(map[string]string)
  95. params["InstanceIds.0"] = instanceId
  96. params["KeyIds.0"] = keypairId
  97. _, err := self.cvmRequest("DisassociateInstancesKeyPairs", params, true)
  98. return err
  99. }
  100. func (self *SRegion) CreateKeyPair(name string) (*SKeypair, error) {
  101. params := make(map[string]string)
  102. params["KeyName"] = name
  103. params["ProjectId"] = "0"
  104. body, err := self.cvmRequest("CreateKeyPair", params, true)
  105. keypair := SKeypair{}
  106. err = body.Unmarshal(&keypair, "KeyPair")
  107. if err != nil {
  108. return nil, err
  109. }
  110. return &keypair, err
  111. }
  112. func (self *SRegion) getKeypairs() ([]SKeypair, error) {
  113. keypairs := []SKeypair{}
  114. for {
  115. parts, total, err := self.GetKeypairs("", []string{}, 0, 50)
  116. if err != nil {
  117. log.Errorf("Get keypairs fail %v", err)
  118. return nil, err
  119. }
  120. keypairs = append(keypairs, parts...)
  121. if len(keypairs) >= total {
  122. break
  123. }
  124. }
  125. return keypairs, nil
  126. }
  127. func (self *SRegion) getFingerprint(publicKey string) (string, error) {
  128. pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey))
  129. if err != nil {
  130. return "", fmt.Errorf("publicKey error %s", err)
  131. }
  132. return ssh.FingerprintLegacyMD5(pk), nil
  133. }
  134. func (self *SRegion) lookUpQcloudKeypair(publicKey string) (string, error) {
  135. keypairs, err := self.getKeypairs()
  136. if err != nil {
  137. return "", err
  138. }
  139. localFiger, err := self.getFingerprint(publicKey)
  140. if err != nil {
  141. return "", err
  142. }
  143. for i := 0; i < len(keypairs); i++ {
  144. finger, err := self.getFingerprint(keypairs[i].PublicKey)
  145. if err != nil {
  146. continue
  147. }
  148. if finger == localFiger {
  149. return keypairs[i].KeyId, nil
  150. }
  151. }
  152. return "", cloudprovider.ErrNotFound
  153. }
  154. func (self *SRegion) syncKeypair(publicKey string) (string, error) {
  155. keypairId, err := self.lookUpQcloudKeypair(publicKey)
  156. if err == nil {
  157. return keypairId, nil
  158. }
  159. prefix, e := goutils.RandomAlphabetic(6)
  160. if e != nil {
  161. return "", fmt.Errorf("publicKey error %s", e)
  162. }
  163. name := prefix + strconv.FormatInt(time.Now().Unix(), 10)
  164. keypair, err := self.ImportKeypair(name, publicKey)
  165. if err != nil {
  166. return "", err
  167. }
  168. return keypair.KeyId, nil
  169. }