modules.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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 modulebase
  15. import (
  16. "fmt"
  17. "sort"
  18. "strings"
  19. "sync"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/util/httputils"
  24. "yunion.io/x/pkg/util/printutils"
  25. "yunion.io/x/pkg/util/sets"
  26. "yunion.io/x/onecloud/pkg/mcclient"
  27. )
  28. type IBaseManager interface {
  29. Version() string
  30. // GetApiVersion() string
  31. GetKeyword() string
  32. KeyString() string
  33. ServiceType() string
  34. EndpointType() string
  35. GetColumns(session *mcclient.ClientSession) []string
  36. List(session *mcclient.ClientSession, params jsonutils.JSONObject) (*printutils.ListResult, error)
  37. }
  38. type ManagerContext struct {
  39. InstanceManager Manager
  40. InstanceId string
  41. }
  42. type Manager interface {
  43. IBaseManager
  44. /* resource list
  45. GET <base_url>/<resource_plural_keyword>
  46. e.g GET <base_url>/alarms
  47. querystring stores in params
  48. e.g. GET <base_url>/alarms?limit=20&offset=20&search=test
  49. return list of resources in json format
  50. { "<resource_plural_keyword>": [ {object details}, {object details}, ...] }, limit: 20, offset: 20, total: 2000}
  51. */
  52. // List(session *mcclient.ClientSession, params jsonutils.JSONObject) (*ListResult, error)
  53. /*
  54. resource list in a context
  55. GET <base_url>/<context_plural_keyword>/<context_id>/<resource_plural_keyword>?querystring
  56. e.g. GET <base_url>/nodes/1/labels?name=xxx
  57. ListInContext(s, params, &modules.Labels, label_id)
  58. return:
  59. { "<resource_plural_keyword>": [ {object details}, {object details}, ...] }, limit: 20, offset: 20, total: 2000}
  60. */
  61. ListInContext(session *mcclient.ClientSession, params jsonutils.JSONObject, ctx Manager, ctxid string) (*printutils.ListResult, error)
  62. ListInContexts(session *mcclient.ClientSession, params jsonutils.JSONObject, ctxs []ManagerContext) (*printutils.ListResult, error)
  63. /*
  64. GET <base_url>/<resource_plural_keyword>/<resource_id>
  65. e.g GET <base_url>/alarams/1
  66. */
  67. Get(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  68. GetInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  69. GetInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  70. GetId(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (string, error)
  71. GetIdInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (string, error)
  72. GetIdInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (string, error)
  73. GetById(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  74. GetByIdInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  75. GetByIdInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  76. GetByName(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  77. GetByNameInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  78. GetByNameInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  79. /*
  80. HEAD <base_url>/<resource_plural_keyword>/<resource_id>
  81. e.g HEAD <base_url>/alarams/1
  82. */
  83. Head(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  84. HeadInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  85. HeadInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  86. BatchGet(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []printutils.SubmitResult
  87. BatchGetInContext(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject, ctx Manager, ctxid string) []printutils.SubmitResult
  88. BatchGetInContexts(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject, ctxs []ManagerContext) []printutils.SubmitResult
  89. GetSpecific(session *mcclient.ClientSession, id string, spec string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  90. GetSpecificInContext(session *mcclient.ClientSession, id string, spec string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  91. GetSpecificInContexts(session *mcclient.ClientSession, id string, spec string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  92. /*
  93. POST <base_url>/<resource_plural_keyword>/<resource_id>
  94. e.g POST <base_url>/alarams/1
  95. */
  96. Create(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  97. CreateInContext(session *mcclient.ClientSession, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  98. CreateInContexts(session *mcclient.ClientSession, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  99. BatchCreate(session *mcclient.ClientSession, params jsonutils.JSONObject, count int) []printutils.SubmitResult
  100. BatchCreateInContext(session *mcclient.ClientSession, params jsonutils.JSONObject, count int, ctx Manager, ctxid string) []printutils.SubmitResult
  101. BatchCreateInContexts(session *mcclient.ClientSession, params jsonutils.JSONObject, count int, ctxs []ManagerContext) []printutils.SubmitResult
  102. Update(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  103. Put(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  104. PutSpecific(session *mcclient.ClientSession, id string, spec string, query jsonutils.JSONObject, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  105. PutInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  106. PutInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  107. BatchUpdate(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []printutils.SubmitResult
  108. BatchParamsUpdate(session *mcclient.ClientSession, idlist []string, params []jsonutils.JSONObject) []printutils.SubmitResult
  109. BatchPut(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []printutils.SubmitResult
  110. BatchPutInContext(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject, ctx Manager, ctxid string) []printutils.SubmitResult
  111. BatchPutInContexts(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject, ctxs []ManagerContext) []printutils.SubmitResult
  112. Patch(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  113. PatchInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  114. PatchInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  115. BatchPatch(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []printutils.SubmitResult
  116. BatchPatchInContext(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject, ctx Manager, ctxid string) []printutils.SubmitResult
  117. BatchPatchInContexts(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject, ctxs []ManagerContext) []printutils.SubmitResult
  118. PerformAction(session *mcclient.ClientSession, id string, action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  119. PerformClassAction(session *mcclient.ClientSession, action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  120. PerformActionInContext(session *mcclient.ClientSession, id string, action string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  121. PerformActionInContexts(session *mcclient.ClientSession, id string, action string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  122. BatchPerformAction(session *mcclient.ClientSession, idlist []string, action string, params jsonutils.JSONObject) []printutils.SubmitResult
  123. BatchPerformActionInContext(session *mcclient.ClientSession, idlist []string, action string, params jsonutils.JSONObject, ctx Manager, ctxid string) []printutils.SubmitResult
  124. BatchPerformActionInContexts(session *mcclient.ClientSession, idlist []string, action string, params jsonutils.JSONObject, ctxs []ManagerContext) []printutils.SubmitResult
  125. Delete(session *mcclient.ClientSession, id string, body jsonutils.JSONObject) (jsonutils.JSONObject, error)
  126. DeleteWithParam(session *mcclient.ClientSession, id string, query jsonutils.JSONObject, body jsonutils.JSONObject) (jsonutils.JSONObject, error)
  127. DeleteInContext(session *mcclient.ClientSession, id string, body jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  128. DeleteInContextWithParam(session *mcclient.ClientSession, id string, query jsonutils.JSONObject, body jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error)
  129. DeleteInContexts(session *mcclient.ClientSession, id string, body jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  130. DeleteInContextsWithParam(session *mcclient.ClientSession, id string, query jsonutils.JSONObject, body jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error)
  131. BatchDelete(session *mcclient.ClientSession, idlist []string, body jsonutils.JSONObject) []printutils.SubmitResult
  132. BatchDeleteWithParam(session *mcclient.ClientSession, idlist []string, query jsonutils.JSONObject, body jsonutils.JSONObject) []printutils.SubmitResult
  133. BatchDeleteInContext(session *mcclient.ClientSession, idlist []string, body jsonutils.JSONObject, ctx Manager, ctxid string) []printutils.SubmitResult
  134. BatchDeleteInContextWithParam(session *mcclient.ClientSession, idlist []string, query jsonutils.JSONObject, body jsonutils.JSONObject, ctx Manager, ctxid string) []printutils.SubmitResult
  135. BatchDeleteInContexts(session *mcclient.ClientSession, idlist []string, body jsonutils.JSONObject, ctxs []ManagerContext) []printutils.SubmitResult
  136. BatchDeleteInContextsWithParam(session *mcclient.ClientSession, idlist []string, query jsonutils.JSONObject, body jsonutils.JSONObject, ctxs []ManagerContext) []printutils.SubmitResult
  137. GetSpecificMethods() sets.String
  138. }
  139. type IResourceManager interface {
  140. Manager
  141. GetMetadata(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  142. SetMetadata(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  143. }
  144. type JointManager interface {
  145. IBaseManager
  146. MasterManager() Manager
  147. SlaveManager() Manager
  148. Get(s *mcclient.ClientSession, mid, sid string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  149. ListDescendent(s *mcclient.ClientSession, mid string, params jsonutils.JSONObject) (*printutils.ListResult, error)
  150. ListDescendent2(s *mcclient.ClientSession, sid string, params jsonutils.JSONObject) (*printutils.ListResult, error)
  151. ListAscendent(s *mcclient.ClientSession, mid string, params jsonutils.JSONObject) (*printutils.ListResult, error)
  152. Attach(s *mcclient.ClientSession, mid, sid string, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  153. BatchAttach(s *mcclient.ClientSession, mid string, sids []string, params jsonutils.JSONObject) []printutils.SubmitResult
  154. BatchAttach2(s *mcclient.ClientSession, mid string, sids []string, params jsonutils.JSONObject) []printutils.SubmitResult
  155. Detach(s *mcclient.ClientSession, mid, sid string, query jsonutils.JSONObject) (jsonutils.JSONObject, error)
  156. BatchDetach(s *mcclient.ClientSession, mid string, sids []string) []printutils.SubmitResult
  157. BatchDetach2(s *mcclient.ClientSession, mid string, sids []string) []printutils.SubmitResult
  158. Update(s *mcclient.ClientSession, mid, sid string, query jsonutils.JSONObject, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  159. BatchUpdate(s *mcclient.ClientSession, mid string, sids []string, query jsonutils.JSONObject, params jsonutils.JSONObject) []printutils.SubmitResult
  160. Patch(s *mcclient.ClientSession, mid, sid string, query jsonutils.JSONObject, params jsonutils.JSONObject) (jsonutils.JSONObject, error)
  161. BatchPatch(s *mcclient.ClientSession, mid string, sids []string, query jsonutils.JSONObject, params jsonutils.JSONObject) []printutils.SubmitResult
  162. }
  163. var (
  164. modules map[string][]IBaseManager
  165. jointModules map[string][]JointManager
  166. )
  167. func resourceKey(mod IBaseManager) string {
  168. return fmt.Sprintf("%s-%s", mod.ServiceType(), mod.KeyString())
  169. }
  170. func resourceKey2(mod IBaseManager) string {
  171. return mod.KeyString()
  172. }
  173. func jointResourceKey(mod1, mod2 IBaseManager) string {
  174. return fmt.Sprintf("%s-%s-%s", mod1.ServiceType(), mod1.KeyString(), mod2.KeyString())
  175. }
  176. func jointResourceKey2(mod1, mod2 IBaseManager) string {
  177. return fmt.Sprintf("%s-%s", mod1.KeyString(), mod2.KeyString())
  178. }
  179. func ensureModuleNotRegistered(mod, newMod IBaseManager, isFatal bool) bool {
  180. modSvcType := mod.ServiceType()
  181. newModSvcType := newMod.ServiceType()
  182. if mod == newMod {
  183. if isFatal {
  184. log.Fatalf("Module %#v duplicate registered, service type: %q", mod, modSvcType)
  185. } else {
  186. return false
  187. }
  188. }
  189. if modSvcType != newModSvcType {
  190. if isFatal {
  191. log.Fatalf("Module %#v already registered, service type is %q.\nSo new module %#v can't be registered, service type is %q", mod, modSvcType, newMod, newModSvcType)
  192. } else {
  193. return false
  194. }
  195. }
  196. return true
  197. }
  198. func Register(m IBaseManager) {
  199. if modules == nil {
  200. modules = make(map[string][]IBaseManager)
  201. }
  202. for i, key := range []string{
  203. resourceKey(m),
  204. resourceKey2(m),
  205. } {
  206. fatal := false
  207. if i == 0 {
  208. fatal = true
  209. }
  210. mods, ok := modules[key]
  211. if !ok {
  212. mods = make([]IBaseManager, 0)
  213. }
  214. skip := false
  215. for i := range mods {
  216. if !ensureModuleNotRegistered(mods[i], m, fatal) {
  217. skip = true
  218. break
  219. }
  220. }
  221. if !skip {
  222. mods = append(mods, m)
  223. modules[key] = mods
  224. }
  225. }
  226. }
  227. func RegisterJointModule(mod IBaseManager) {
  228. jointMod, ok := mod.(JointManager)
  229. if ok { // also a joint manager
  230. for _, jointKey := range []string{
  231. jointResourceKey(jointMod.MasterManager(), jointMod.SlaveManager()),
  232. jointResourceKey2(jointMod.MasterManager(), jointMod.SlaveManager()),
  233. } {
  234. jointMods, ok := jointModules[jointKey]
  235. if !ok {
  236. jointMods = make([]JointManager, 0)
  237. }
  238. skip := false
  239. for i := range jointMods {
  240. if !ensureModuleNotRegistered(jointMods[i], jointMod, false) {
  241. skip = true
  242. break
  243. }
  244. }
  245. if !skip {
  246. jointModules[jointKey] = append(jointMods, jointMod)
  247. }
  248. }
  249. }
  250. }
  251. var jointModulesLock *sync.Mutex
  252. func init() {
  253. jointModulesLock = &sync.Mutex{}
  254. }
  255. func registerAllJointModules() {
  256. jointModulesLock.Lock()
  257. defer jointModulesLock.Unlock()
  258. if jointModules == nil {
  259. jointModules = make(map[string][]JointManager)
  260. for modname := range modules {
  261. for i := range modules[modname] {
  262. RegisterJointModule(modules[modname][i])
  263. }
  264. }
  265. }
  266. }
  267. func _getModule(session *mcclient.ClientSession, name string) (IBaseManager, error) {
  268. mods, ok := modules[name]
  269. if !ok {
  270. return nil, fmt.Errorf("No such module %s", name)
  271. }
  272. if len(mods) == 1 {
  273. return mods[0], nil
  274. }
  275. for _, mod := range mods {
  276. url, e := session.GetServiceURL(mod.ServiceType(), mod.EndpointType(), httputils.POST)
  277. if e != nil {
  278. return nil, errors.Wrap(e, "session.GetServiceURL")
  279. }
  280. _, ver := mcclient.SplitVersionedURL(url)
  281. log.Debugf("url: %s ver: %s mod.Version: %s", url, ver, mod.Version())
  282. if strings.EqualFold(ver, mod.Version()) {
  283. return mod, nil
  284. }
  285. }
  286. return nil, fmt.Errorf("Version mismatch")
  287. }
  288. func GetModule(session *mcclient.ClientSession, name string) (Manager, error) {
  289. bm, e := _getModule(session, name)
  290. if e != nil {
  291. return nil, e
  292. }
  293. m, ok := bm.(Manager)
  294. if ok {
  295. return m, nil
  296. } else {
  297. return nil, fmt.Errorf("Module %s not a Manager", name)
  298. }
  299. }
  300. func GetJointModule(session *mcclient.ClientSession, name string) (JointManager, error) {
  301. bm, e := _getModule(session, name)
  302. if e != nil {
  303. return nil, e
  304. }
  305. m, ok := bm.(JointManager)
  306. if ok {
  307. return m, nil
  308. } else {
  309. return nil, fmt.Errorf("Module %s not a Manager", name)
  310. }
  311. }
  312. func GetJointModule2(session *mcclient.ClientSession, mod1 Manager, mod2 Manager) (JointManager, error) {
  313. registerAllJointModules()
  314. for _, key := range []string{
  315. jointResourceKey(mod1, mod2),
  316. jointResourceKey2(mod1, mod2),
  317. } {
  318. mods, ok := jointModules[key]
  319. if !ok {
  320. continue
  321. }
  322. for _, mod := range mods {
  323. url, e := session.GetServiceVersionURL(mod.ServiceType(), mod.EndpointType(), httputils.POST)
  324. if e != nil {
  325. return nil, e
  326. }
  327. _, ver := mcclient.SplitVersionedURL(url)
  328. if strings.EqualFold(ver, mod.Version()) {
  329. return mod, nil
  330. }
  331. }
  332. return nil, fmt.Errorf("Version mismatch")
  333. }
  334. return nil, fmt.Errorf("No such joint module: %s", jointResourceKey(mod1, mod2))
  335. }
  336. func GetRegisterdModules() ([]string, []string) {
  337. registerAllJointModules()
  338. ret := make([]string, 0)
  339. for k := range modules {
  340. ret = append(ret, k)
  341. }
  342. sort.Strings(ret)
  343. ret2 := make([]string, 0)
  344. for k := range jointModules {
  345. ret2 = append(ret2, k)
  346. }
  347. sort.Strings(ret2)
  348. return ret, ret2
  349. }