script_apply.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. "fmt"
  18. "sync"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/sets"
  22. api "yunion.io/x/onecloud/pkg/apis/devtool"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  24. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  25. "yunion.io/x/onecloud/pkg/mcclient"
  26. )
  27. type SScriptApply struct {
  28. db.SStatusStandaloneResourceBase
  29. ScriptId string `width:"36" nullable:"false" index:"true"`
  30. GuestId string `width:"36" nullable:"false" index:"true"`
  31. //
  32. Args jsonutils.JSONObject
  33. TryTimes int
  34. ArgsGenerator string `width:"36" nullable:"false"`
  35. }
  36. type SScriptApplyManager struct {
  37. db.SStatusStandaloneResourceBaseManager
  38. Session *sScriptApplySession
  39. }
  40. var ScriptApplyManager *SScriptApplyManager
  41. func init() {
  42. ScriptApplyManager = &SScriptApplyManager{
  43. SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
  44. SScriptApply{},
  45. "scriptapply_tbl",
  46. "scriptapply",
  47. "scirptapplys",
  48. ),
  49. Session: newScriptApplySession(),
  50. }
  51. ScriptApplyManager.SetVirtualObject(ScriptApplyManager)
  52. }
  53. func (sam *SScriptApplyManager) createScriptApply(ctx context.Context, scriptId, guestId string, args map[string]interface{}, argsGenerator string) (*SScriptApply, error) {
  54. sa := &SScriptApply{
  55. ScriptId: scriptId,
  56. GuestId: guestId,
  57. Args: jsonutils.Marshal(args),
  58. ArgsGenerator: argsGenerator,
  59. }
  60. err := ScriptApplyManager.TableSpec().Insert(ctx, sa)
  61. sa.SetModelManager(ScriptApplyManager, sa)
  62. return sa, err
  63. }
  64. func (sa *SScriptApply) StartApply(ctx context.Context, userCred mcclient.TokenCredential) (err error) {
  65. if ok := ScriptApplyManager.Session.CheckAndSet(sa.Id); !ok {
  66. return fmt.Errorf("script %s is applying to server %s", sa.ScriptId, sa.GuestId)
  67. }
  68. defer func() {
  69. if err != nil {
  70. ScriptApplyManager.Session.Remove(sa.Id)
  71. }
  72. }()
  73. // check try times
  74. script, err := sa.Script()
  75. if err != nil {
  76. return err
  77. }
  78. if sa.TryTimes >= script.MaxTryTimes {
  79. return fmt.Errorf("The times to try has exceeded the maximum times %d setted by the script", script.MaxTryTimes)
  80. }
  81. _, err = db.Update(sa, func() error {
  82. sa.TryTimes += 1
  83. sa.Status = api.SCRIPT_APPLY_STATUS_APPLYING
  84. return nil
  85. })
  86. if err != nil {
  87. return errors.Wrap(err, "unable to update scriptapply")
  88. }
  89. err = sa.startApplyScriptTask(ctx, userCred, "")
  90. if err != nil {
  91. f := false
  92. _, err = ScriptApplyRecordManager.createRecordWithResult(ctx, sa.GetId(), &f, fmt.Sprintf("unabel to start ApplyScriptTask: %v", err))
  93. if err != nil {
  94. return errors.Wrap(err, "unable to record")
  95. }
  96. ScriptApplyManager.Session.Remove(sa.Id)
  97. }
  98. return nil
  99. }
  100. func (sa *SScriptApply) startApplyScriptTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  101. task, err := taskman.TaskManager.NewTask(ctx, "ApplyScriptTask", sa, userCred, nil, "", parentTaskId)
  102. if err != nil {
  103. return err
  104. }
  105. task.ScheduleRun(nil)
  106. return nil
  107. }
  108. func (sa *SScriptApply) StopApply(userCred mcclient.TokenCredential, record *SScriptApplyRecord, success bool, failCode string, reason string) error {
  109. var status string
  110. if success {
  111. status = api.SCRIPT_APPLY_STATUS_READY
  112. if record != nil {
  113. record.Succeed(reason)
  114. }
  115. } else {
  116. status = api.SCRIPT_APPLY_RECORD_FAILED
  117. if record != nil {
  118. record.Fail(failCode, reason)
  119. }
  120. }
  121. sa.SetStatus(context.Background(), userCred, status, "")
  122. ScriptApplyManager.Session.Remove(sa.Id)
  123. return nil
  124. }
  125. func (sa *SScriptApply) Script() (*SScript, error) {
  126. obj, err := ScriptManager.FetchById(sa.ScriptId)
  127. if err != nil {
  128. return nil, errors.Wrapf(err, "unable to fetch Script %s", sa.Id)
  129. }
  130. s := obj.(*SScript)
  131. s.SetModelManager(ScriptManager, s)
  132. return s, nil
  133. }
  134. type sScriptApplySession struct {
  135. mux *sync.Mutex
  136. applyingOnes sets.String
  137. }
  138. func newScriptApplySession() *sScriptApplySession {
  139. return &sScriptApplySession{
  140. mux: &sync.Mutex{},
  141. applyingOnes: sets.NewString(),
  142. }
  143. }
  144. func (sas *sScriptApplySession) CheckAndSet(id string) bool {
  145. sas.mux.Lock()
  146. defer sas.mux.Unlock()
  147. if sas.applyingOnes.Has(id) {
  148. return false
  149. }
  150. sas.applyingOnes.Insert(id)
  151. return true
  152. }
  153. func (sas *sScriptApplySession) Remove(id string) {
  154. sas.mux.Lock()
  155. defer sas.mux.Unlock()
  156. sas.applyingOnes.Delete(id)
  157. }