ansibleplaybooks_validator.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 models
  15. import (
  16. "context"
  17. "strings"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/pkg/util/regutils"
  20. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  21. "yunion.io/x/onecloud/pkg/httperrors"
  22. mcclient "yunion.io/x/onecloud/pkg/mcclient"
  23. mcclient_auth "yunion.io/x/onecloud/pkg/mcclient/auth"
  24. mcclient_models "yunion.io/x/onecloud/pkg/mcclient/models"
  25. "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  26. "yunion.io/x/onecloud/pkg/util/ansible"
  27. )
  28. type ValidatorAnsiblePlaybook struct {
  29. validators.Validator
  30. Playbook *ansible.Playbook
  31. userCred mcclient.TokenCredential
  32. }
  33. func NewAnsiblePlaybookValidator(key string, userCred mcclient.TokenCredential) *ValidatorAnsiblePlaybook {
  34. v := &ValidatorAnsiblePlaybook{
  35. Validator: validators.Validator{Key: key},
  36. userCred: userCred,
  37. }
  38. v.SetParent(v)
  39. return v
  40. }
  41. func (v *ValidatorAnsiblePlaybook) Validate(ctx context.Context, data *jsonutils.JSONDict) error {
  42. pb := ansible.NewPlaybook()
  43. err := data.Unmarshal(pb, "playbook")
  44. if err != nil {
  45. return httperrors.NewBadRequestError("unmarshaling json: %v", err)
  46. }
  47. hosts := pb.Inventory.Hosts
  48. for i := range hosts {
  49. name := strings.TrimSpace(hosts[i].Name)
  50. if len(name) == 0 {
  51. return httperrors.NewBadRequestError("empty host name")
  52. }
  53. defaultUsername := ansible.PUBLIC_CLOUD_ANSIBLE_USER
  54. switch {
  55. case regutils.MatchIP4Addr(name):
  56. case strings.HasPrefix(name, "host:"):
  57. var err error
  58. name = strings.TrimSpace(name[len("host:"):])
  59. name, err = v.getHostAccessIp(name)
  60. if err != nil {
  61. return err
  62. }
  63. defaultUsername = "root"
  64. case strings.HasPrefix(name, "server:"):
  65. name = name[len("server:"):]
  66. fallthrough
  67. default:
  68. var err error
  69. name = strings.TrimSpace(name)
  70. name, err = v.getServerIp(name)
  71. if err != nil {
  72. return err
  73. }
  74. }
  75. hosts[i].Name = name
  76. if username, _ := hosts[i].GetVar("ansible_user"); username == "" {
  77. if defaultUsername != "" {
  78. hosts[i].SetVar("ansible_user", defaultUsername)
  79. }
  80. }
  81. }
  82. // add LF for privateKey
  83. if len(pb.PrivateKey) > 0 && pb.PrivateKey[len(pb.PrivateKey)-1] != 10 {
  84. pb.PrivateKey = append(pb.PrivateKey, 10)
  85. }
  86. pbJson := jsonutils.Marshal(pb)
  87. if serialized := pbJson.String(); len(serialized) > PlaybookMaxBytes {
  88. return httperrors.NewBadRequestError("playbook too big, got %d bytes, exceeding %d",
  89. len(serialized), PlaybookMaxBytes)
  90. }
  91. v.Playbook = pb
  92. data.Set("playbook", pbJson)
  93. return nil
  94. }
  95. func (v *ValidatorAnsiblePlaybook) getHostAccessIp(name string) (string, error) {
  96. sess := mcclient_auth.GetSession(context.Background(), v.userCred, "")
  97. hostJson, err := compute.Hosts.Get(sess, name, nil)
  98. if err != nil {
  99. return "", httperrors.NewBadRequestError("cannot find host %s", name)
  100. }
  101. host := &mcclient_models.Host{}
  102. if err := hostJson.Unmarshal(host); err != nil {
  103. return "", httperrors.NewBadRequestError("unmarshal host %s: %v", name, err)
  104. }
  105. if host.AccessIp == "" {
  106. return "", httperrors.NewBadRequestError("host %s has no access ip", name)
  107. }
  108. return host.AccessIp, nil
  109. }
  110. func (v *ValidatorAnsiblePlaybook) getServerIp(name string) (string, error) {
  111. sess := mcclient_auth.GetSession(context.Background(), v.userCred, "")
  112. serverJson, err := compute.Servers.Get(sess, name, nil)
  113. if err != nil {
  114. return "", httperrors.NewBadRequestError("find server %s: %v", name, err)
  115. }
  116. server := &mcclient_models.Server{}
  117. if err := serverJson.Unmarshal(server); err != nil {
  118. return "", httperrors.NewBadRequestError("unmarshal server %s: %v", name, err)
  119. }
  120. serverNetworks, err := mcclient_models.ParseServerNetworkDetailedString(server.Networks)
  121. if err != nil {
  122. return "", httperrors.NewConflictError("parse networks of %s: %v", name, err)
  123. }
  124. ips := serverNetworks.GetPrivateIPs()
  125. if len(ips) == 0 {
  126. return "", httperrors.NewBadRequestError("server %s has no private ips", name)
  127. }
  128. name = ips[0].String()
  129. return name, nil
  130. }