helper.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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 cmdline
  15. import (
  16. "fmt"
  17. "yunion.io/x/jsonutils"
  18. "yunion.io/x/pkg/util/fileutils"
  19. "yunion.io/x/pkg/util/regutils"
  20. "yunion.io/x/onecloud/pkg/apis/compute"
  21. "yunion.io/x/onecloud/pkg/apis/scheduler"
  22. )
  23. type resourceConfigOutput struct {
  24. keyword string
  25. keywordPlural string
  26. }
  27. func newResouceConfigOutput(kw, kws string) *resourceConfigOutput {
  28. return &resourceConfigOutput{keyword: kw, keywordPlural: kws}
  29. }
  30. func (o resourceConfigOutput) Keyword() string {
  31. return o.keyword
  32. }
  33. func (o resourceConfigOutput) KeywordPlural() string {
  34. return o.keywordPlural
  35. }
  36. type iResourcesOutput interface {
  37. Keyword() string
  38. KeywordPlural() string
  39. NewConfig() interface{}
  40. ParseDesc(desc string, idx int) (interface{}, error)
  41. Add(config interface{})
  42. Resources() interface{}
  43. }
  44. func fetchResourceConfigsByJSON(
  45. obj jsonutils.JSONObject,
  46. output iResourcesOutput,
  47. ) error {
  48. if obj == nil {
  49. obj = jsonutils.NewDict()
  50. }
  51. keywordPlural := output.KeywordPlural()
  52. keyword := output.Keyword()
  53. if obj.Contains(keywordPlural) {
  54. err := obj.Unmarshal(output.Resources(), keywordPlural)
  55. return err
  56. }
  57. configs := jsonutils.GetArrayOfPrefix(obj, keyword)
  58. for idx, config := range configs {
  59. configJson, ok := config.(*jsonutils.JSONDict)
  60. resConfig := output.NewConfig()
  61. if ok {
  62. if err := configJson.Unmarshal(resConfig); err != nil {
  63. return err
  64. }
  65. } else {
  66. configStr, err := config.GetString()
  67. if err != nil {
  68. return err
  69. }
  70. resConfig, err = output.ParseDesc(configStr, idx)
  71. if err != nil {
  72. return err
  73. }
  74. }
  75. output.Add(resConfig)
  76. }
  77. return nil
  78. }
  79. type diskConfigOutput struct {
  80. *resourceConfigOutput
  81. disks []*compute.DiskConfig
  82. }
  83. func newDiskConfigOutput() *diskConfigOutput {
  84. return &diskConfigOutput{
  85. resourceConfigOutput: newResouceConfigOutput("disk", "disks"),
  86. }
  87. }
  88. func (output *diskConfigOutput) Disks() []*compute.DiskConfig {
  89. return output.disks
  90. }
  91. func (output *diskConfigOutput) Resources() interface{} {
  92. return &output.disks
  93. }
  94. func (output *diskConfigOutput) NewConfig() interface{} {
  95. return new(compute.DiskConfig)
  96. }
  97. func (output *diskConfigOutput) Add(config interface{}) {
  98. output.disks = append(output.disks, config.(*compute.DiskConfig))
  99. }
  100. func (output *diskConfigOutput) ParseDesc(desc string, idx int) (interface{}, error) {
  101. return ParseDiskConfig(desc, idx)
  102. }
  103. func FetchDiskConfigsByJSON(obj jsonutils.JSONObject) ([]*compute.DiskConfig, error) {
  104. output := newDiskConfigOutput()
  105. err := fetchResourceConfigsByJSON(obj, output)
  106. return output.Disks(), err
  107. }
  108. type netConfigOutput struct {
  109. *resourceConfigOutput
  110. nets []*compute.NetworkConfig
  111. }
  112. func newNetworkConfigOutput() *netConfigOutput {
  113. return &netConfigOutput{
  114. resourceConfigOutput: newResouceConfigOutput("net", "nets"),
  115. }
  116. }
  117. func (output *netConfigOutput) Networks() []*compute.NetworkConfig {
  118. return output.nets
  119. }
  120. func (output *netConfigOutput) Resources() interface{} {
  121. return &output.nets
  122. }
  123. func (output *netConfigOutput) NewConfig() interface{} {
  124. return new(compute.NetworkConfig)
  125. }
  126. func (output *netConfigOutput) Add(config interface{}) {
  127. output.nets = append(output.nets, config.(*compute.NetworkConfig))
  128. }
  129. func (output *netConfigOutput) ParseDesc(desc string, idx int) (interface{}, error) {
  130. return ParseNetworkConfig(desc, idx)
  131. }
  132. func FetchNetworkConfigsByJSON(obj jsonutils.JSONObject) ([]*compute.NetworkConfig, error) {
  133. output := newNetworkConfigOutput()
  134. err := fetchResourceConfigsByJSON(obj, output)
  135. return output.Networks(), err
  136. }
  137. type schedtagConfigOutput struct {
  138. *resourceConfigOutput
  139. tags []*compute.SchedtagConfig
  140. }
  141. func newSchedtagConfigOutput() *schedtagConfigOutput {
  142. return &schedtagConfigOutput{
  143. resourceConfigOutput: newResouceConfigOutput("schedtag", "schedtags"),
  144. }
  145. }
  146. func (output *schedtagConfigOutput) Schedtags() []*compute.SchedtagConfig {
  147. return output.tags
  148. }
  149. func (output *schedtagConfigOutput) Resources() interface{} {
  150. return &output.tags
  151. }
  152. func (output *schedtagConfigOutput) NewConfig() interface{} {
  153. return new(compute.SchedtagConfig)
  154. }
  155. func (output *schedtagConfigOutput) Add(config interface{}) {
  156. output.tags = append(output.tags, config.(*compute.SchedtagConfig))
  157. }
  158. func (output *schedtagConfigOutput) ParseDesc(desc string, _ int) (interface{}, error) {
  159. return ParseSchedtagConfig(desc)
  160. }
  161. func FetchSchedtagConfigsByJSON(obj jsonutils.JSONObject) ([]*compute.SchedtagConfig, error) {
  162. output := newSchedtagConfigOutput()
  163. if err := fetchResourceConfigsByJSON(obj, output); err != nil {
  164. return nil, err
  165. }
  166. if len(output.tags) == 0 {
  167. // compatible with old api
  168. schedtags, _ := obj.GetMap("aggregate_strategy")
  169. if schedtags != nil {
  170. for id, strategyObj := range schedtags {
  171. strategy, _ := strategyObj.GetString()
  172. output.tags = append(output.tags, &compute.SchedtagConfig{
  173. Id: id,
  174. Strategy: strategy,
  175. })
  176. }
  177. }
  178. }
  179. return output.tags, nil
  180. }
  181. type isoDevConfigOutput struct {
  182. *resourceConfigOutput
  183. devs []*compute.IsolatedDeviceConfig
  184. }
  185. func newIsoDevConfigOutput() *isoDevConfigOutput {
  186. return &isoDevConfigOutput{
  187. resourceConfigOutput: newResouceConfigOutput("isolated_device", "isolated_devices"),
  188. }
  189. }
  190. func (output *isoDevConfigOutput) Devs() []*compute.IsolatedDeviceConfig {
  191. return output.devs
  192. }
  193. func (output *isoDevConfigOutput) Resources() interface{} {
  194. return &output.devs
  195. }
  196. func (output *isoDevConfigOutput) NewConfig() interface{} {
  197. return new(compute.IsolatedDeviceConfig)
  198. }
  199. func (output *isoDevConfigOutput) Add(config interface{}) {
  200. output.devs = append(output.devs, config.(*compute.IsolatedDeviceConfig))
  201. }
  202. func (output *isoDevConfigOutput) ParseDesc(desc string, idx int) (interface{}, error) {
  203. return ParseIsolatedDevice(desc, idx)
  204. }
  205. func FetchIsolatedDeviceConfigsByJSON(obj jsonutils.JSONObject) ([]*compute.IsolatedDeviceConfig, error) {
  206. output := newIsoDevConfigOutput()
  207. err := fetchResourceConfigsByJSON(obj, output)
  208. return output.devs, err
  209. }
  210. type bmDiskConfigOutput struct {
  211. *resourceConfigOutput
  212. configs []*compute.BaremetalDiskConfig
  213. }
  214. func newbmDiskConfigOutput() *bmDiskConfigOutput {
  215. return &bmDiskConfigOutput{
  216. resourceConfigOutput: newResouceConfigOutput("baremetal_disk_config", "baremetal_disk_configs"),
  217. }
  218. }
  219. func (output *bmDiskConfigOutput) Devs() []*compute.BaremetalDiskConfig {
  220. return output.configs
  221. }
  222. func (output *bmDiskConfigOutput) Resources() interface{} {
  223. return &output.configs
  224. }
  225. func (output *bmDiskConfigOutput) NewConfig() interface{} {
  226. return new(compute.BaremetalDiskConfig)
  227. }
  228. func (output *bmDiskConfigOutput) Add(config interface{}) {
  229. output.configs = append(output.configs, config.(*compute.BaremetalDiskConfig))
  230. }
  231. func (output *bmDiskConfigOutput) ParseDesc(desc string, idx int) (interface{}, error) {
  232. return ParseBaremetalDiskConfig(desc)
  233. }
  234. func FetchBaremetalDiskConfigsByJSON(obj jsonutils.JSONObject) ([]*compute.BaremetalDiskConfig, error) {
  235. output := newbmDiskConfigOutput()
  236. err := fetchResourceConfigsByJSON(obj, output)
  237. return output.configs, err
  238. }
  239. func FetchServerConfigsByJSON(obj jsonutils.JSONObject) (*compute.ServerConfigs, error) {
  240. conf := new(compute.ServerConfigs)
  241. if err := obj.Unmarshal(conf); err != nil {
  242. return nil, err
  243. }
  244. if instanceType, _ := obj.GetString("sku"); instanceType != "" {
  245. conf.InstanceType = instanceType
  246. }
  247. var err error
  248. conf.Disks, err = FetchDiskConfigsByJSON(obj)
  249. if err != nil {
  250. return nil, err
  251. }
  252. conf.Networks, err = FetchNetworkConfigsByJSON(obj)
  253. if err != nil {
  254. return nil, err
  255. }
  256. conf.Schedtags, err = FetchSchedtagConfigsByJSON(obj)
  257. if err != nil {
  258. return nil, err
  259. }
  260. conf.IsolatedDevices, err = FetchIsolatedDeviceConfigsByJSON(obj)
  261. if err != nil {
  262. return nil, err
  263. }
  264. conf.BaremetalDiskConfigs, err = FetchBaremetalDiskConfigsByJSON(obj)
  265. if err != nil {
  266. return nil, err
  267. }
  268. return conf, nil
  269. }
  270. func FetchScheduleInputByJSON(obj jsonutils.JSONObject) (*scheduler.ScheduleInput, error) {
  271. input := new(scheduler.ScheduleInput)
  272. err := obj.Unmarshal(input)
  273. if err != nil {
  274. return nil, err
  275. }
  276. conf := &input.ServerConfig
  277. if obj.Contains("scheduler") {
  278. obj, _ = obj.Get("scheduler")
  279. obj.Unmarshal(conf)
  280. }
  281. conf.ServerConfigs, err = FetchServerConfigsByJSON(obj)
  282. if err != nil {
  283. return nil, err
  284. }
  285. if input.Domain == "" {
  286. input.Domain = jsonutils.GetAnyString(obj, []string{"project_domain", "domain_id"})
  287. }
  288. if input.Project == "" {
  289. input.Project = jsonutils.GetAnyString(obj, []string{"project", "project_id"})
  290. }
  291. return input, nil
  292. }
  293. func FetchDeployConfigsByJSON(obj jsonutils.JSONObject) ([]*compute.DeployConfig, error) {
  294. deploys := make([]*compute.DeployConfig, 0)
  295. if obj.Contains("deploy_configs") {
  296. err := obj.Unmarshal(&deploys, "deploy_configs")
  297. return deploys, err
  298. }
  299. for idx := 0; obj.Contains(fmt.Sprintf("deploy.%d.path", idx)); idx += 1 {
  300. path, _ := obj.GetString(fmt.Sprintf("deploy.%d.path", idx))
  301. action, _ := obj.GetString(fmt.Sprintf("deploy.%d.action", idx))
  302. content, _ := obj.GetString(fmt.Sprintf("deploy.%d.content", idx))
  303. deploys = append(deploys, &compute.DeployConfig{Path: path, Action: action, Content: content})
  304. }
  305. return deploys, nil
  306. }
  307. func FetchServerCreateInputByJSON(obj jsonutils.JSONObject) (*compute.ServerCreateInput, error) {
  308. input := new(compute.ServerCreateInput)
  309. // compatible with vmem_size string
  310. memSizeObj, _ := obj.Get("vmem_size")
  311. if memSizeObj != nil {
  312. if _, ok := memSizeObj.(*jsonutils.JSONString); ok {
  313. memStr, err := memSizeObj.GetString()
  314. if err != nil {
  315. return nil, err
  316. }
  317. if !regutils.MatchSize(memStr) {
  318. return nil, fmt.Errorf("Invalid memory size string: %s, Memory size must be number[+unit], like 256M, 1G or 256", memStr)
  319. }
  320. vmemSize, err := fileutils.GetSizeMb(memStr, 'M', 1024)
  321. if err != nil {
  322. return nil, err
  323. }
  324. obj.(*jsonutils.JSONDict).Set("vmem_size", jsonutils.NewInt(int64(vmemSize)))
  325. }
  326. }
  327. err := obj.Unmarshal(input)
  328. if err != nil {
  329. return nil, err
  330. }
  331. config, err := FetchServerConfigsByJSON(obj)
  332. if err != nil {
  333. return nil, err
  334. }
  335. input.ServerConfigs = config
  336. deployConfigs, err := FetchDeployConfigsByJSON(obj)
  337. if err != nil {
  338. return nil, err
  339. }
  340. input.DeployConfigs = deployConfigs
  341. if skuName := jsonutils.GetAnyString(obj, []string{"sku", "flavor", "instance_type"}); skuName != "" {
  342. input.InstanceType = skuName
  343. }
  344. if keypair := jsonutils.GetAnyString(obj, []string{"keypair", "keypair_id"}); keypair != "" {
  345. input.KeypairId = keypair
  346. }
  347. if secgroup := jsonutils.GetAnyString(obj, []string{"secgroup", "secgroup_id", "secgrp_id"}); len(secgroup) != 0 {
  348. input.SecgroupId = secgroup
  349. }
  350. input.Secgroups, _ = jsonutils.GetStringArray(obj, "secgroups")
  351. return input, nil
  352. }
  353. func FetchDiskCreateInputByJSON(data jsonutils.JSONObject) (*compute.DiskCreateInput, error) {
  354. config := new(compute.DiskConfig)
  355. input := &compute.DiskCreateInput{
  356. DiskConfig: config,
  357. }
  358. if err := data.Unmarshal(input); err != nil {
  359. return nil, err
  360. }
  361. if data.Contains("disk") {
  362. desc, err := data.GetString("disk")
  363. config, err = ParseDiskConfig(desc, -1)
  364. if err != nil {
  365. return nil, err
  366. }
  367. input.DiskConfig = config
  368. }
  369. if storageId := jsonutils.GetAnyString(data, []string{"storage_id", "storage"}); storageId != "" {
  370. input.Storage = storageId
  371. }
  372. return input, nil
  373. }