Compare commits

...

223 Commits

Author SHA1 Message Date
Zexi Li
6e479d596f Merge pull request #11744 from ioito/automated-cherry-pick-of-#11743-upstream-release-3.7
Automated cherry pick of #11743: fix(climc): add version list command
2021-07-28 20:04:00 +08:00
Qu Xuan
4c0b8d8318 fix(climc): add version list command 2021-07-28 19:47:11 +08:00
Zexi Li
e730e2b1ae Merge pull request #11735 from zhaoxiangchun/automated-cherry-pick-of-#11734-upstream-release-3.7
Automated cherry pick of #11734: feat(climc):  register  billsanalysis  climc
2021-07-28 14:47:04 +08:00
zhaoxiangchun
6152c9be01 feat(climc): register billsanalysis climc 2021-07-28 14:35:27 +08:00
Zexi Li
e8c6b625e5 Merge pull request #11732 from zexi/automated-cherry-pick-of-#11673-upstream-release-3.7
Automated cherry pick of #11673: feat(climc): add enable monitor minio component command
2021-07-27 18:08:12 +08:00
Zexi Li
92a8880f99 feat(climc): add enable monitor minio component command 2021-07-27 18:07:46 +08:00
Zexi Li
a0058edc16 Merge pull request #11730 from swordqiu/automated-cherry-pick-of-#11729-upstream-release-3.7
Automated cherry pick of #11729: fix: simplify SQL for distinct field query of tenant or domain names
2021-07-27 10:29:43 +08:00
Zexi Li
f630133ab3 Merge pull request #11728 from ioito/automated-cherry-pick-of-#11727-upstream-release-3.7
Automated cherry pick of #11727: feat(region): add status count filter by params
2021-07-27 10:29:07 +08:00
Qiu Jian
db876b4480 fix: simplify SQL for distinct field query of tenant or domain names 2021-07-27 01:19:23 +08:00
Zexi Li
994857dffb Merge pull request #11725 from rainzm/automated-cherry-pick-of-#11724-upstream-release-3.7
Automated cherry pick of #11724: fix(region): fetch zone before syncing promise cloud provider storages
2021-07-26 18:56:43 +08:00
Zexi Li
3078ea2af3 Merge pull request #11721 from ioito/automated-cherry-pick-of-#11720-upstream-release-3.7
Automated cherry pick of #11720: fix(region): openstack ip pre allocate
2021-07-26 18:44:02 +08:00
Qu Xuan
5cdf5051a5 feat(region): add status count filter by params 2021-07-26 17:57:00 +08:00
rainzm
6c30b04365 fix(region): fetch zone before syncing promise cloud provider storages 2021-07-26 17:19:52 +08:00
Qu Xuan
2e720737a5 fix(region): openstack ip pre allocate 2021-07-26 15:27:53 +08:00
Zexi Li
89255ecc79 Merge pull request #11716 from ioito/automated-cherry-pick-of-#11715-upstream-release-3.7
Automated cherry pick of #11715: fix(region): cpu desc too long
2021-07-26 14:36:04 +08:00
Qu Xuan
5f4b9c2b51 fix(region): cpu desc too long 2021-07-26 10:05:58 +08:00
yunion-ci-robot
30ac3d3f40 Merge pull request #11712 from zexi/automated-cherry-pick-of-#11711-upstream-release-3.7
Automated cherry pick of #11711: fix(host): find same vendor iommu_group devices
2021-07-25 00:13:31 +08:00
Zexi Li
c0f3090d2a fix(host): find same vendor iommu_group devices 2021-07-24 21:42:23 +08:00
Zexi Li
379797e2aa Merge pull request #11708 from ioito/automated-cherry-pick-of-#11707-upstream-release-3.7
Automated cherry pick of #11707: fix(region): update qcloud secgroup rule
2021-07-23 18:22:24 +08:00
Qu Xuan
ed7d6715af fix(region): update qcloud secgroup rule 2021-07-23 17:42:18 +08:00
Zexi Li
eb8b4368fc Merge pull request #11692 from ioito/automated-cherry-pick-of-#11691-upstream-release-3.7
Automated cherry pick of #11691: fix(region): account aksk error
2021-07-23 14:22:52 +08:00
Zexi Li
21d0d98f59 Merge pull request #11702 from ioito/automated-cherry-pick-of-#11701-upstream-release-3.7
Automated cherry pick of #11701: fix(region): azure quota sync
2021-07-23 14:22:19 +08:00
Qu Xuan
c0e969368b fix(region): azure quota sync 2021-07-22 19:35:24 +08:00
Zexi Li
47f7fc1a35 Merge pull request #11694 from rainzm/automated-cherry-pick-of-#11693-upstream-release-3.7
Automated cherry pick of #11693: feat: support install monitor agent in baremetal
2021-07-22 15:29:53 +08:00
Zexi Li
2cac694816 Merge pull request #11696 from swordqiu/automated-cherry-pick-of-#11695-upstream-release-3.7
Automated cherry pick of #11695: fix: qemu-img create disk may fail to preallocation=metadata enable for large disk
2021-07-22 15:27:15 +08:00
Qiu Jian
1f7d9e2cf8 fix: qemu-img create disk may fail to preallocation=metadata enable for large disk
error report: failed to flush the refcount block cache: File too large
2021-07-22 12:17:19 +08:00
rainzm
bea1592741 feat: support install monitor agent in baremetal 2021-07-21 19:51:54 +08:00
Qu Xuan
898fa5d160 fix(region): account aksk error 2021-07-21 19:34:58 +08:00
Zexi Li
19591a3ad2 Merge pull request #11687 from rainzm/automated-cherry-pick-of-#11686-upstream-release-3.7
Automated cherry pick of #11686: Use custom version Telegraf as monitor agent
2021-07-20 21:16:09 +08:00
Zexi Li
716f77d280 Merge pull request #11683 from ioito/automated-cherry-pick-of-#11681-upstream-release-3.7
Automated cherry pick of #11681: fix(keystone): policy filter by role
2021-07-20 21:13:38 +08:00
rainzm
c3a652bad2 feat: update file-repo version 2021-07-20 19:44:54 +08:00
rainzm
09666490ca feat: use yunion's customized version of telegraf in file-repo 2021-07-20 19:44:54 +08:00
Zexi Li
f3fa282434 Merge pull request #11665 from rainzm/automated-cherry-pick-of-#11663-upstream-release-3.7
Automated cherry pick of #11663: feat(hostdeployer): change UserAdd to CheckOrAddUser
2021-07-20 18:54:56 +08:00
Qu Xuan
4722fae114 fix(keystone): policy filter by role 2021-07-20 15:50:34 +08:00
Zexi Li
992f54defe Merge pull request #11680 from zexi/automated-cherry-pick-of-#11678-upstream-release-3.7
Automated cherry pick of #11678: fix(build): baremetal arm64 build
2021-07-19 20:28:47 +08:00
Zexi Li
c12ed7b8e0 fix(build): baremetal arm64 build 2021-07-19 20:21:46 +08:00
Zexi Li
1348c76fc9 Merge pull request #11675 from ioito/automated-cherry-pick-of-#11674-upstream-release-3.7
Automated cherry pick of #11674: fix(region): rds network sync
2021-07-19 18:50:12 +08:00
Qu Xuan
8ea004084e fix(region): return rds networks info 2021-07-19 17:30:13 +08:00
Qu Xuan
bd5bd0ae70 fix(region): rds network sync 2021-07-19 17:30:13 +08:00
Zexi Li
afcfea3bda Merge pull request #11668 from ioito/automated-cherry-pick-of-#11667-upstream-release-3.7
Automated cherry pick of #11667: fix(keystone): avoid sql error
2021-07-19 14:22:01 +08:00
Qu Xuan
c629e7fce3 fix(keystone): avoid sql error 2021-07-19 14:04:25 +08:00
rainzm
48729ae9bc feat(hostdeployer): change UserAdd to CheckOrAddUser
If the user already exists, use the existing user and its information; otherwise, create a new user
2021-07-19 11:21:15 +08:00
Zexi Li
96ec7c0142 Merge pull request #11659 from ioito/automated-cherry-pick-of-#11658-upstream-release-3.7
Automated cherry pick of #11658: fix(region): sync auzre subscription health status
2021-07-16 11:24:44 +08:00
Zexi Li
ff9dadc3a7 Merge pull request #11662 from ioito/automated-cherry-pick-of-#11661-upstream-release-3.7
Automated cherry pick of #11661: fix(climc): json tag
2021-07-16 11:14:06 +08:00
Qu Xuan
760427c884 fix(climc): json tag 2021-07-16 11:08:02 +08:00
Qu Xuan
1c54d09ec2 fix(region): sync auzre subscription health status 2021-07-16 10:58:12 +08:00
Zexi Li
b1a8414949 Merge pull request #11652 from swordqiu/automated-cherry-pick-of-#11641-upstream-release-3.7
Automated cherry pick of #11641: feature: allow server switch network without service interruption
2021-07-15 19:17:35 +08:00
Zexi Li
cac7bf92bd Merge pull request #11648 from zexi/automated-cherry-pick-of-#11647-upstream-release-3.7
Automated cherry pick of #11647: fix(baremetal): compatible with SN empty of MegaRaid
2021-07-15 19:16:19 +08:00
Zexi Li
db125a6df3 fix(baremetal): compatible with SN empty of MegaRaid 2021-07-15 10:30:18 +08:00
Qiu Jian
b2a3742fbb fix: migrate interface before commit desc 2021-07-14 21:29:46 +08:00
Qiu Jian
9faf2d553e minor fixes 2021-07-14 21:29:46 +08:00
Qiu Jian
ad8a5ed953 fix: add codes to switch bridge of ovs port 2021-07-14 21:29:46 +08:00
Qiu Jian
a9ada013cf feature: allow server switch network without service interruption 2021-07-14 21:29:46 +08:00
Zexi Li
98abe8185e Merge pull request #11651 from bistuzx/automated-cherry-pick-of-#11650-upstream-release-3.7
Automated cherry pick of #11650: feat(meter): add meter cost conversion
2021-07-14 18:52:21 +08:00
bistuzx@163.com
c069baa46e add meter cost conversion 2021-07-14 18:10:21 +08:00
Zexi Li
14b8e7ce59 Merge pull request #11636 from ioito/automated-cherry-pick-of-#11580-upstream-release-3.7
Automated cherry pick of #11580: fix(region): update manager name
2021-07-14 11:08:11 +08:00
Zexi Li
25278ead71 Merge pull request #11639 from ioito/automated-cherry-pick-of-#11638-upstream-release-3.7
Automated cherry pick of #11638: fix(region): remove debug info
2021-07-13 20:10:57 +08:00
Qu Xuan
9384e81c88 fix(region): remove debug info 2021-07-13 17:27:53 +08:00
Qu Xuan
2ef57b2d19 fix(region): update manager name 2021-07-13 10:51:48 +08:00
Zexi Li
667cfe4e53 Merge pull request #11604 from rainzm/automated-cherry-pick-of-#11600-upstream-release-3.7
Automated cherry pick of #11600: fix(region): sync storage before syncing host in syncOnPremiseCloudProviderInfo
2021-07-13 10:46:43 +08:00
Zexi Li
9ce8c93b4b Merge pull request #11631 from ioito/automated-cherry-pick-of-#11627-upstream-release-3.7
Automated cherry pick of #11627: fix(region): allocate server eip without hostwire restrict
2021-07-12 18:40:18 +08:00
Qu Xuan
092cc351b2 fix(region): allocate server eip without hostwire restrict 2021-07-12 14:25:57 +08:00
yunion-ci-robot
368ef90425 Merge pull request #11629 from tb365/automated-cherry-pick-of-#11628-upstream-release-3.7
Automated cherry pick of #11628: fix(keystone): user not found error fix
2021-07-12 14:03:02 +08:00
tb365
285b0f2523 fix(keystone): user not found error fix 2021-07-12 13:54:22 +08:00
Zexi Li
aa87a342a7 Merge pull request #11621 from rainzm/automated-cherry-pick-of-#11592-upstream-release-3.7
Automated cherry pick of #11592: feat(devtool): use server forward direct for guest with kvm hypervisor
2021-07-12 10:28:34 +08:00
Zexi Li
a62be4a708 Merge pull request #11618 from zhaoxiangchun/automated-cherry-pick-of-#11617-upstream-release-3.7
Automated cherry pick of #11617: fix(monitor): fix monitor resourece update
2021-07-12 10:27:38 +08:00
Zexi Li
a0331e094d Merge pull request #11623 from rainzm/automated-cherry-pick-of-#11622-upstream-release-3.7
Automated cherry pick of #11622: fix(region): set DefaultSysDiskBackend as empty for esxi guest
2021-07-10 10:54:11 +08:00
rainzm
162c3315c0 fix(region): sync storage before syncing host in syncOnPremiseCloudProviderInfo
场景:重新构建了某个存储,相当于把之前某个存储上的所有虚拟机迁移到一个新的存储上。

因为没有syncStorage,所以在同步syncHostStorge的时候无法disconnect host
和 没有的storage,这是因为storage上还有host的虚拟机。syncHostStorages
会失败,storageCache 也就不会同步,上面的icloudImage也不会同步。
2021-07-09 19:21:10 +08:00
rainzm
742b05540d fix(region): set DefaultSysDiskBackend as empty for esxi guest 2021-07-09 19:13:48 +08:00
yunion-ci-robot
7d13ffd432 Merge pull request #11612 from zexi/automated-cherry-pick-of-#11609-upstream-release-3.7
Automated cherry pick of #11609: fix(baremetal): use ipmitool power reset when redfish power on error
2021-07-09 18:53:00 +08:00
rainzm
9d17f7091b feat(devtool): use server forward direct for guest with kvm hypervisor 2021-07-09 17:10:17 +08:00
Zexi Li
0ed305cd0b fix(baremetal): use ipmitool power reset when redfish power on error 2021-07-09 14:47:08 +08:00
zhaoxiangchun
c27cec0195 fix(monitor): fix monitor resourece update
1.通过region返回的obj更新监控资源时 remove掉id信息
2021-07-09 13:09:07 +08:00
Zexi Li
09f2812a29 Merge pull request #11605 from zhaoxiangchun/automated-cherry-pick-of-#11603-upstream-release-3.7
Automated cherry pick of #11603: fix(monitor):  alert policy use ownerId when update
2021-07-09 12:07:11 +08:00
Zexi Li
e58e611c00 Merge pull request #11613 from swordqiu/automated-cherry-pick-of-#11610-upstream-release-3.7
Automated cherry pick of #11610: fix: host detach wire not update netinterface
2021-07-09 11:53:29 +08:00
Qiu Jian
9630e1b7db fix: host detach wire not update netinterface 2021-07-09 10:45:28 +08:00
zhaoxiangchun
3b8eaaf554 fix(monitor): alert policy use ownerId when update
1.根据参数中的project和domain属性调用FetchOwnerId方法,然后确定报警策略归属并进行监控查询过滤
2021-07-09 10:17:47 +08:00
yunion-ci-robot
01bc96d4c5 Merge pull request #11594 from zexi/automated-cherry-pick-of-#11563-upstream-release-3.7
Automated cherry pick of #11563: feat(host): aware of kubelet eviction config
2021-07-08 20:16:59 +08:00
Zexi Li
63fc152fcd Merge pull request #11598 from rainzm/automated-cherry-pick-of-#11597-upstream-release-3.7
Automated cherry pick of #11597: fix(host-deployer): make SKVMGuestLVMPartition work find
2021-07-08 18:40:17 +08:00
rainzm
233b97977d fix(host-deployer): make SKVMGuestLVMPartition work fine
1. add needChangeName to indicate whether to change the name when
   putting down
2. remove unnecessary IsVgActice
3. findPartitions from /dev/{vgname}/{lvname} or
   /dev/mapper/{vgname}-{lvname}
2021-07-08 18:18:16 +08:00
Zexi Li
35b0f69399 Merge pull request #11589 from zhaoxiangchun/automated-cherry-pick-of-#11587-upstream-release-3.7
Automated cherry pick of #11587: feat(monitor): update monitor resource overview
2021-07-08 10:30:52 +08:00
Zexi Li
580f9ca3cd feat(host): aware of kubelet eviction config 2021-07-07 21:29:55 +08:00
zhaoxiangchun
90300c1afb feat(monitor): update monitor resource overview
1.调整监控总览-报警资源逻辑
启用禁用策略时对报警资源进行对应的挂载和解绑
2021-07-07 20:37:41 +08:00
Zexi Li
ee0ae2a35d Merge pull request #11584 from rainzm/automated-cherry-pick-of-#11583-upstream-release-3.7
Automated cherry pick of #11583: fix(region): handle the error of RequestGuestCreateAllDisks
2021-07-07 20:29:14 +08:00
rainzm
cdfb16ec1b fix(region): handle the error of RequestGuestCreateAllDisks 2021-07-07 15:46:23 +08:00
Zexi Li
198e42ea95 Merge pull request #11571 from rainzm/automated-cherry-pick-of-#11570-upstream-release-3.7
Automated cherry pick of #11570: feat(hostdeployer): change the way fo GetLoginAccount in windows
2021-07-06 22:22:01 +08:00
yunion-ci-robot
827891d7fd Merge pull request #11576 from zexi/automated-cherry-pick-of-#11574-upstream-release-3.7
Automated cherry pick of #11574: fix(host-deployer): detect UEFI supported not correct
2021-07-06 19:51:58 +08:00
Zexi Li
15a160c876 fix(host-deployer): detect UEFI supported not correct 2021-07-06 19:32:30 +08:00
rainzm
b3f298afdb feat(hostdeployer): change the way fo GetLoginAccount in windows
首先,如果不是win10,并且 windowsDefaultAdminUser 置为 true,以及
Administrator 没有lock,那么使用 Administrator。
否则,优先使用第一个没有被锁定且不是 Administrator 的user,如果最后没有
符合条件的user,且Adminstrator 没有被lock,就是用 Administrator。
否则,报错。
2021-07-06 17:37:43 +08:00
yunion-ci-robot
703a89e53f Merge pull request #11566 from zexi/automated-cherry-pick-of-#11564-upstream-release-3.7
Automated cherry pick of #11564: feat(host): add openEuler rootFs driver
2021-07-06 15:29:00 +08:00
Zexi Li
d112a0a277 feat(host): add openEuler rootFs driver 2021-07-06 14:50:07 +08:00
Zexi Li
f77d490626 Merge pull request #11561 from zexi/automated-cherry-pick-of-#11560-upstream-release-3.7
Automated cherry pick of #11560: update OWNERS
2021-07-05 15:55:32 +08:00
Zexi Li
4a3230aee5 update OWNERS 2021-07-05 15:54:31 +08:00
Zexi Li
0d756ad0b4 Merge pull request #11555 from swordqiu/automated-cherry-pick-of-#11554-upstream-release-3.7
Automated cherry pick of #11554: fix: add cloudroot as system account, so as not using normal user id
2021-07-04 10:26:38 +08:00
Qiu Jian
490e7e4ef7 fix: add cloudroot as system account, so as not using normal user id 2021-07-03 22:25:01 +08:00
Zexi Li
0578ab7e34 Merge pull request #11544 from zexi/automated-cherry-pick-of-#11542-upstream-release-3.7
Automated cherry pick of #11542: fix(climc): update climc-base image to 20210701
2021-07-02 11:28:48 +08:00
Zexi Li
5673d1d114 fix(climc): update climc-base image to 20210701 2021-07-02 10:14:58 +08:00
Zexi Li
f49ff18247 Merge pull request #11540 from swordqiu/automated-cherry-pick-of-#11539-upstream-release-3.7
Automated cherry pick of #11539: fix: do not use ntfsresize to resize NTFS partition
2021-07-02 10:01:48 +08:00
Qiu Jian
b21c1f1a8b fix: do not use ntfsresize to resize NTFS partition
This makes resizing windows 2003 ntfs partition non-functional
2021-07-02 09:16:20 +08:00
Zexi Li
26fecfb1f7 Merge pull request #11531 from ioito/automated-cherry-pick-of-#11530-upstream-release-3.7
Automated cherry pick of #11530: fix(webconsole): aliyun vnc windows ctl+alt+del
2021-06-30 20:16:25 +08:00
Qu Xuan
8cae1408f7 fix(webconsole): aliyun vnc windows ctl+alt+del 2021-06-30 20:01:56 +08:00
Zexi Li
617dc611c0 Merge pull request #11523 from zhaoxiangchun/automated-cherry-pick-of-#11522-upstream-release-3.7
Automated cherry pick of #11522: fix(monitor): update alert panel scope by  alert dashboard
2021-06-30 10:37:46 +08:00
Zexi Li
33e17c9749 Merge pull request #11528 from zhaoxiangchun/automated-cherry-pick-of-#11527-upstream-release-3.7
Automated cherry pick of #11527: fix(monitor): fix monitor process alert
2021-06-30 10:25:59 +08:00
zhaoxiangchun
2488a5dab1 fix(monitor): fix monitor process alert
修复进程监控报警后,没有触发前端报警提示的问题
2021-06-30 09:49:40 +08:00
yunion-ci-robot
dbd6035616 Merge pull request #11525 from zexi/automated-cherry-pick-of-#11524-upstream-release-3.7
Automated cherry pick of #11524: fix(scheduler): baremetal network free address out of count
2021-06-29 23:24:16 +08:00
Zexi Li
1f9a66d00f fix(scheduler): baremetal network free address out of count 2021-06-29 20:25:03 +08:00
zhaoxiangchun
f4cb3d2beb fix(monitor): update alert panel scope by alert dashboard 2021-06-29 17:24:23 +08:00
Zexi Li
0bb8f4984b Merge pull request #11519 from swordqiu/automated-cherry-pick-of-#11518-upstream-release-3.7
Automated cherry pick of #11518: fix(host): allow server directory a symbol link to directory in other location
2021-06-29 10:00:16 +08:00
Qiu Jian
79f8013376 fix(host): allow server directory a symbol link to directory in other location 2021-06-29 00:03:49 +08:00
Zexi Li
353f21ffa2 Merge pull request #11516 from zhaoxiangchun/automated-cherry-pick-of-#11514-upstream-release-3.7
Automated cherry pick of #11514: fix(monitor): fix alert record not return resource details
2021-06-28 20:22:26 +08:00
zhaoxiangchun
6ee987c875 fix(monitor): fix alert record not return resource details 2021-06-28 19:44:50 +08:00
Zexi Li
f9b5a82acd Merge pull request #11504 from ioito/automated-cherry-pick-of-#11503-upstream-release-3.7
Automated cherry pick of #11503: fi(region): avoid opslog without resource id
2021-06-28 19:41:52 +08:00
Zexi Li
67603523dc Merge pull request #11508 from ioito/automated-cherry-pick-of-#11507-upstream-release-3.7
Automated cherry pick of #11507: fix(region): avoid panic when sync snapshot project
2021-06-28 19:36:44 +08:00
Zexi Li
e39ed2efc4 Merge pull request #11510 from rainzm/automated-cherry-pick-of-#11509-upstream-release-3.7
Automated cherry pick of #11509: fix: get datacenter of host via GetDatacenter
2021-06-28 19:35:40 +08:00
rainzm
d00578d6eb fix: get datacenter of host via GetDatacenter 2021-06-28 18:17:12 +08:00
Qu Xuan
8f7653c14c fix(region): avoid panic when sync snapshot project 2021-06-28 18:14:53 +08:00
Qu Xuan
b448719335 fi(region): avoid opslog without resource id 2021-06-28 17:20:25 +08:00
Zexi Li
7b9f2dff61 Merge pull request #11499 from zexi/automated-cherry-pick-of-#11498-upstream-release-3.7
Automated cherry pick of #11498: fix(region): baremetal server change ip address reuse
2021-06-28 15:07:12 +08:00
Zexi Li
55011704c0 fix(region): baremetal server change ip address reuse 2021-06-28 14:44:58 +08:00
Zexi Li
9575725dfa Merge pull request #11493 from zhaoxiangchun/automated-cherry-pick-of-#11492-upstream-release-3.7
Automated cherry pick of #11492: feat(climc): update meter dimension climc
2021-06-28 11:36:47 +08:00
zhaoxiangchun
4dc9ef631f feat(climc): update meter dimension climc 2021-06-26 22:22:25 +08:00
Zexi Li
532a45d109 Merge pull request #11487 from rainzm/automated-cherry-pick-of-#10970-upstream-release-3.7
Automated cherry pick of #10970: feat(scheduler): optimize the speed of network predicate
2021-06-25 18:27:27 +08:00
rainzm
c317f05b78 feat: add interface INetworkNicCountGetter 2021-06-25 15:58:30 +08:00
rainzm
5741782cca feat(scheduler): optimize the speed of network predicate 2021-06-25 15:58:30 +08:00
Zexi Li
da452e23c8 Merge pull request #11479 from rainzm/automated-cherry-pick-of-#11478-upstream-release-3.7
Automated cherry pick of #11478: fix(notify): distinct field of receivers
2021-06-24 20:11:07 +08:00
rainzm
8304b37773 fix(notify): distinct field of receivers 2021-06-24 10:40:42 +08:00
Zexi Li
b0fcef5c6a Merge pull request #11472 from zhaoxiangchun/automated-cherry-pick-of-#11471-upstream-release-3.7
Automated cherry pick of #11471: feat(monitor): add jenkins metric desc
2021-06-24 10:02:44 +08:00
Zexi Li
bc55b8b276 Merge pull request #11474 from rainzm/automated-cherry-pick-of-#11473-upstream-release-3.7
Automated cherry pick of #11473: Sync VMware resource faster
2021-06-24 10:01:34 +08:00
rainzm
882d885aa4 feat(esxi): disable sync cloudimage from image cache 2021-06-23 17:05:50 +08:00
rainzm
d791cba145 feat(esxi): reduce the number of requests and the amount of data transferred 2021-06-23 17:05:50 +08:00
rainzm
7cf931cc16 feat(region): add ProhibitRefreshingCloudImage for options 2021-06-23 17:05:50 +08:00
zhaoxiangchun
0f55252c5b feat(monitor): add jenkins metric desc 2021-06-23 15:29:22 +08:00
Zexi Li
6298415e7b Merge pull request #11459 from ioito/automated-cherry-pick-of-#11453-upstream-release-3.7
Automated cherry pick of #11453: fix(region): ignore qcloud vm start error
2021-06-23 11:54:50 +08:00
yunion-ci-robot
38384ca1ec Merge pull request #11467 from zexi/automated-cherry-pick-of-#11457-upstream-release-3.7
Automated cherry pick of #11457: feat(host): support netplan configuration
2021-06-23 11:39:11 +08:00
Zexi Li
4c5cd45efd Merge pull request #11464 from ioito/automated-cherry-pick-of-#11463-upstream-release-3.7
Automated cherry pick of #11463: fix(hostman): show server status changed reason
2021-06-23 10:53:30 +08:00
Zexi Li
edb7c6050b Merge pull request #11462 from zhaoxiangchun/automated-cherry-pick-of-#11461-upstream-release-3.7
Automated cherry pick of #11461: fix(monitor): fix monitor overview
2021-06-23 10:51:41 +08:00
Zexi Li
e1e6a72b4f feat(host): support netplan configuration 2021-06-23 10:38:07 +08:00
Qu Xuan
3c844caa4b fix(hostman): show server status changed reason 2021-06-22 17:55:04 +08:00
zhaoxiangchun
8c51294fe7 fix(monitor): fix monitor overview
1.监控总览中资源报警统计支持项目钻取
2. 资源报警状态修复
2021-06-22 17:11:52 +08:00
Qu Xuan
8679dbee27 fix(region): ignore qcloud vm start error 2021-06-22 10:18:08 +08:00
Zexi Li
c4cd0cabdc Merge pull request #11456 from zhaoxiangchun/automated-cherry-pick-of-#11454-upstream-release-3.7
Automated cherry pick of #11454: fix(monitor): exit monitor engine in time when happen err
2021-06-21 23:49:48 +08:00
zhaoxiangchun
894d12f903 fix(monitor): exit monitor engine in time when happen err 2021-06-21 16:12:24 +08:00
Zexi Li
f127585611 Merge pull request #11449 from zexi/automated-cherry-pick-of-#11448-upstream-release-3.7
Automated cherry pick of #11448: fix(baremetal): remove bundle libs build
2021-06-21 10:42:58 +08:00
Zexi Li
3258a1c262 fix(baremetal): remove bundle libs build 2021-06-21 10:32:49 +08:00
Zexi Li
86e07c0afc Merge pull request #11440 from rainzm/automated-cherry-pick-of-#11439-upstream-release-3.7
Automated cherry pick of #11439: feat(notify): filter all recipients in this domain and recipients who have joined projects in this domain
2021-06-21 00:34:24 +08:00
Zexi Li
3a93e1754e Merge pull request #11444 from zhaoxiangchun/automated-cherry-pick-of-#11428-upstream-release-3.7-1624013747
Automated cherry pick of #11428: feat(monitor) 3.7 add monitor resource overview
2021-06-21 00:33:57 +08:00
yunion-ci-robot
44ea206e28 Merge pull request #11435 from zexi/automated-cherry-pick-of-#11433-upstream-release-3.7
Automated cherry pick of #11433: fix(region,scheduler): baremetal reuse ip
2021-06-19 22:39:57 +08:00
zhaoxiangchun
ae085eace6 utomated cherry pick of #11428: feat(monitor) 3.7 add monitor resource overview 2021-06-18 18:57:29 +08:00
zhaoxiangchun
629a3c55fd feat(monitor) 3.7 add monitor resource overview
1. 监控中增加资源统计
2. 资源在报警总览中的状态:
   init--未设置告警;alerting--发生告警;/attach--已关联策略并且报警消息正常
3.只涉及宿主机和虚拟机

https://bug.yunion.io/zentao/task-view-3130.html
2021-06-18 18:55:51 +08:00
Zexi Li
8459cb7ba2 Merge pull request #11442 from ioito/automated-cherry-pick-of-#11441-upstream-release-3.7
Automated cherry pick of #11441: fix(region): skip disabled project mapping
2021-06-18 18:32:29 +08:00
Qu Xuan
92b0d323f1 fix(region): skip disabled project mapping 2021-06-18 18:05:25 +08:00
Zexi Li
322f795d88 Merge pull request #11420 from ioito/automated-cherry-pick-of-#11419-upstream-release-3.7
Automated cherry pick of #11419: fix(region): add project filter for cloudprovider
2021-06-18 16:21:42 +08:00
Zexi Li
ebcf3f5f9f Merge pull request #11437 from ioito/automated-cherry-pick-of-#11436-upstream-release-3.7
Automated cherry pick of #11436: fix(region): manager distinct field
2021-06-18 16:21:14 +08:00
Zexi Li
4087fa4593 fix(region,scheduler): baremetal reuse ip 2021-06-18 15:46:27 +08:00
rainzm
c1d792dc8a feat(notify): filter all recipients in this domain and recipients who have joined projects in this domain 2021-06-18 15:22:42 +08:00
Qu Xuan
9e5408856f fix(region): manager distinct field 2021-06-18 14:20:21 +08:00
Zexi Li
6d87de376f Merge pull request #11431 from zexi/automated-cherry-pick-of-#11430-upstream-release-3.7
Automated cherry pick of #11430: fix(region): clean schedule cache when host add or delete netif
2021-06-18 11:16:14 +08:00
Zexi Li
5054e618cb fix(region): clean schedule cache when host add or delete netif 2021-06-18 11:04:03 +08:00
yunion-ci-robot
39fab4b3ae Merge pull request #11426 from bistuzx/automated-cherry-pick-of-#11425-upstream-release-3.7
Automated cherry pick of #11425: add meter billing exchange rate module
2021-06-17 23:54:54 +08:00
bistuzx@163.com
fe622c89d3 add module billing exchange rate 2021-06-17 19:47:24 +08:00
Qu Xuan
b7c3e53731 fix(region): add project filter for cloudprovider 2021-06-17 17:19:21 +08:00
Zexi Li
c793d5cda7 Merge pull request #11403 from ioito/automated-cherry-pick-of-#11402-upstream-release-3.7
Automated cherry pick of #11402: fix(region): show project mapping managers info
2021-06-17 14:57:07 +08:00
Zexi Li
310dac6b3e Merge pull request #11414 from swordqiu/automated-cherry-pick-of-#11413-upstream-release-3.7
Automated cherry pick of #11413: fix: support windows 2003
2021-06-17 10:18:35 +08:00
Zexi Li
8eaa4a0653 Merge pull request #11416 from swordqiu/automated-cherry-pick-of-#11415-upstream-release-3.7
Automated cherry pick of #11415: fix: do not resize LVM paritition and skip and return success
2021-06-17 09:48:13 +08:00
Qiu Jian
a481666baa fix: support windows 2003 2021-06-17 09:45:27 +08:00
Qiu Jian
2d1884da54 fix: do not resize LVM paritition and skip and return success 2021-06-17 01:55:12 +08:00
yunion-ci-robot
119fa29e77 Merge pull request #11341 from zexi/automated-cherry-pick-of-#11205-upstream-release-3.7
Automated cherry pick of #11205: feat(baremetal): support management of none BMC host
2021-06-16 23:42:53 +08:00
Zexi Li
c799d89764 Merge pull request #11411 from ioito/automated-cherry-pick-of-#11404-upstream-release-3.7
Automated cherry pick of #11404: fix(region): ignore qcloud bw pkg error
2021-06-16 20:09:59 +08:00
Zexi Li
cd76efd19e Merge pull request #11407 from yousong/automated-cherry-pick-of-#11406-upstream-release-3.7
Automated cherry pick of #11406: webconsole: wait zombies
2021-06-16 20:09:02 +08:00
Qu Xuan
f36688d4b5 fix(region): ignore qcloud bw pkg error 2021-06-16 19:42:41 +08:00
Yousong Zhou
bcc8f0b581 webconsole: wait zombies 2021-06-16 19:33:51 +08:00
Qu Xuan
ad5d667587 fix(region): show project mapping managers info 2021-06-16 17:31:41 +08:00
Zexi Li
e76592de73 fix(baremetal): record uefi info 2021-06-16 12:49:56 +08:00
Zexi Li
382962fd0e fix(baremetal): nvme allocable 2021-06-16 12:49:56 +08:00
Zexi Li
0f74c9ba0a feat(baremetal): add UEFI related util 2021-06-16 12:49:56 +08:00
Zexi Li
30d4b3b7cd fix(baremetal): close ssh test client 2021-06-16 12:49:56 +08:00
Zexi Li
160a6e4dbb feat(baremetal): support management of none BMC host 2021-06-16 12:49:56 +08:00
Zexi Li
bf26f445a6 Merge pull request #11398 from ioito/automated-cherry-pick-of-#11397-upstream-release-3.7
Automated cherry pick of #11397: fix(region): add status resource statistic
2021-06-15 16:32:06 +08:00
Zexi Li
59fafadda6 Merge pull request #11393 from ioito/automated-cherry-pick-of-#11376-upstream-release-3.7
Automated cherry pick of #11376: fix(region): qcloud bandwidth pkg
2021-06-15 16:31:06 +08:00
Qu Xuan
638d01485e fix(region): add status resource statistic 2021-06-15 14:16:23 +08:00
Qu Xuan
1de62d60ed fix(region): qcloud bandwidth pkg 2021-06-11 19:17:53 +08:00
Zexi Li
91e833db42 Merge pull request #11381 from rainzm/automated-cherry-pick-of-#11380-upstream-release-3.7
Automated cherry pick of #11380: fix(notify): clean verifiedNote when marking verified
2021-06-11 17:49:53 +08:00
Zexi Li
7d3b5d2fcb Merge pull request #11377 from ioito/automated-cherry-pick-of-#11375-upstream-release-3.7
Automated cherry pick of #11375: fix(host): update rbd storage capacity
2021-06-11 17:46:34 +08:00
Zexi Li
02a17c1753 Merge pull request #11368 from ioito/automated-cherry-pick-of-#11367-upstream-release-3.7
Automated cherry pick of #11367: fix(region): support cloudprovider bind project mapping
2021-06-11 17:45:54 +08:00
rainzm
66ad8ace31 fix(notify): clean verifiedNote when marking verified 2021-06-11 10:08:20 +08:00
Qu Xuan
8f4ae62aa4 fix(host): update rbd storage capacity 2021-06-11 09:50:09 +08:00
Qu Xuan
9c41deb42c fix(region): support cloudprovider bind project mapping 2021-06-10 15:55:17 +08:00
Zexi Li
e9f7d87688 Merge pull request #11348 from zhaoxiangchun/automated-cherry-pick-of-#11347-upstream-release-3.7
Automated cherry pick of #11347: feat(mcclient): add bills dimension climc
2021-06-10 05:34:01 +08:00
Zexi Li
0b5461b707 Merge pull request #11370 from ioito/automated-cherry-pick-of-#11369-upstream-release-3.7
Automated cherry pick of #11369: fix(host): get ceph used capacity
2021-06-10 05:32:41 +08:00
Qu Xuan
2d791dd542 fix(host): get ceph used capacity 2021-06-09 19:25:36 +08:00
zhaoxiangchun
910372ea0c feat(mcclient): add bills dimension climc 2021-06-09 11:16:41 +08:00
Zexi Li
302a411629 Merge pull request #11307 from ioito/automated-cherry-pick-of-#11306-upstream-release-3.7
Automated cherry pick of #11306: fix(region): skip server migrate quota check
2021-06-08 23:29:29 +08:00
Zexi Li
f25b015143 Merge pull request #11339 from rainzm/automated-cherry-pick-of-#11338-upstream-release-3.7
Automated cherry pick of #11338: Add some tags to the monitoring data generated by the agent
2021-06-08 23:27:53 +08:00
Zexi Li
bf08a413d3 Merge pull request #11342 from ioito/automated-cherry-pick-of-#11340-upstream-release-3.7
Automated cherry pick of #11340: fix(cloudid): huawei group role attach and detach
2021-06-08 23:14:18 +08:00
Zexi Li
200911ef38 Merge pull request #11350 from ioito/automated-cherry-pick-of-#11349-upstream-release-3.7
Automated cherry pick of #11349: fix(cloudid): avoid duplicate create saml provider
2021-06-08 23:13:54 +08:00
Zexi Li
cb3aadd014 Merge pull request #11355 from ioito/automated-cherry-pick-of-#11354-upstream-release-3.7
Automated cherry pick of #11354: feat(apigateway): support export dict keys
2021-06-08 23:11:54 +08:00
Zexi Li
c84d543df2 Merge pull request #11358 from ioito/automated-cherry-pick-of-#11357-upstream-release-3.7
Automated cherry pick of #11357: fix(region): avoid storage update not work
2021-06-08 23:10:05 +08:00
Zexi Li
494a9041b3 Merge pull request #11362 from ioito/automated-cherry-pick-of-#11361-upstream-release-3.7
Automated cherry pick of #11361: fix(region): validate disk status when create snapshot
2021-06-08 23:08:16 +08:00
Qu Xuan
9f50a53945 fix(region): validate disk status when create snapshot 2021-06-08 20:09:11 +08:00
Qu Xuan
d11fcc7945 fix(region): avoid storage update not work 2021-06-08 17:33:53 +08:00
Qu Xuan
ebe101d9ab feat(apigateway): support export dict keys 2021-06-08 16:24:05 +08:00
Qu Xuan
87c1c0e290 fix(cloudid): avoid duplicate create saml provider 2021-06-08 14:19:17 +08:00
yunion-ci-robot
6ccfcbf0da Merge pull request #11312 from ioito/automated-cherry-pick-of-#11311-upstream-release-3.7
Automated cherry pick of #11311: fix(region): huawei disk tags
2021-06-08 10:50:26 +08:00
Qu Xuan
cf7f5f6805 fix(cloudid): huawei group role attach and detach 2021-06-07 18:18:08 +08:00
Zexi Li
22a5b36817 Merge pull request #11333 from ioito/automated-cherry-pick-of-#11332-upstream-release-3.7
Automated cherry pick of #11332: fix(region): validate attached disk size and backend
2021-06-07 17:43:48 +08:00
Zexi Li
8da358513a Merge pull request #11336 from zhaoxiangchun/automated-cherry-pick-of-#11335-upstream-release-3.7
Automated cherry pick of #11335: fix(telegraf-raid-plugin): add image-telegraf-raid-plugin in Makefile
2021-06-07 17:42:38 +08:00
rainzm
02252842e7 feat(build): change file repo version in Dockerfile.ansibleserver 2021-06-07 17:18:57 +08:00
rainzm
21c33d4844 feat(devtool): add some tags 2021-06-07 17:18:57 +08:00
rainzm
e7dc0213f6 fix(anisbleserver): support complex yaml config in ansibleplaybook_instance 2021-06-07 17:18:57 +08:00
zhaoxiangchun
754c2e62ee fix(telegraf-raid-plugin): add image-telegraf-raid-plugin in Makefile 2021-06-07 16:20:08 +08:00
Qu Xuan
c6e99bf802 fix(region): validate attached disk size and backend 2021-06-07 15:44:18 +08:00
Qu Xuan
f13c01d20f fix(region): skip server migrate quota check 2021-06-07 10:13:48 +08:00
Zexi Li
92d4e3cf7a Merge pull request #11327 from ioito/automated-cherry-pick-of-#11326-upstream-release-3.7
Automated cherry pick of #11326: fix(region): sync tags with new guest
2021-06-06 00:54:42 +08:00
Zexi Li
3efd579564 Merge pull request #11323 from zhaoxiangchun/automated-cherry-pick-of-#11320-upstream-release-3.7
Automated cherry pick of #11320: fix: 修复云账号和宿主机报警问题
2021-06-05 12:16:40 +08:00
Qu Xuan
4484a2082b fix(region): sync tags with new guest 2021-06-04 23:10:20 +08:00
Zexi Li
d2cfe35296 Merge pull request #11298 from tb365/automated-cherry-pick-of-#11297-upstream-release-3.7
Automated cherry pick of #11297: fix(region): lb local cert sync fix
2021-06-04 21:09:54 +08:00
Zexi Li
f548d76116 Merge pull request #11300 from swordqiu/automated-cherry-pick-of-#11299-upstream-release-3.7
Automated cherry pick of #11299: fix: hpssacli should skip empty slots
2021-06-04 21:04:26 +08:00
Zexi Li
fbcbe46a8e Merge pull request #11319 from ioito/automated-cherry-pick-of-#11318-upstream-release-3.7
Automated cherry pick of #11318: fix(region): avoid guest delete not with disks
2021-06-04 19:46:31 +08:00
zhaoxiangchun
1389d2176e fix: 修复云账号和宿主机报警问题
1.云账号报警时过滤掉已经禁用的云账号
2.修复宿主机报警时资源名称重复的问题
2021-06-04 19:24:36 +08:00
Qu Xuan
64a86f7ccd fix(region): avoid guest delete not with disks 2021-06-04 19:17:21 +08:00
Qu Xuan
5b5310c6ee fix(region): huawei disk tags 2021-06-04 14:37:13 +08:00
Qiu Jian
162dd766ff fix: hpssacli should skip empty slots
hpssacli may fail when detect disks on empty slots, which cause raid
detection failure
2021-06-03 19:35:53 +08:00
tb365
1c7c3e05bd fix(region): lb local cert sync fix 2021-06-03 18:51:37 +08:00
242 changed files with 7574 additions and 1418 deletions

View File

@@ -18,4 +18,6 @@ assignees: ''
**Environment**:
- OS (e.g: `cat /etc/os-release`):
- Kernel (e.g. `uname -a`):
- Others:
<!--
- Version (e.g. `climc version-list`):
-->

View File

@@ -329,6 +329,9 @@ image:
.PHONY: image
image-telegraf-raid-plugin:
VERSION=release-1.6.1 ARCH=all make image telegraf-raid-plugin
%:
@:

6
OWNERS
View File

@@ -4,12 +4,6 @@ reviewers:
- ioito
- swordqiu
- tb365
- wanyaoqi
- yousong
- zhaoxiangchun
- zhasm
approvers:
- swordqiu
- yousong
- wanyaoqi
- Zexi

View File

@@ -1,7 +1,7 @@
FROM registry.cn-beijing.aliyuncs.com/yunionio/ansibleserver-base:v1.0.3
# install playbook and telegraf install pkg
COPY --from=registry.cn-beijing.aliyuncs.com/yunionio/file-repo:v0.1.2 /opt/yunion/playbook /opt/yunion/playbook
COPY --from=registry.cn-beijing.aliyuncs.com/yunionio/file-repo:v0.1.2 /opt/yunion/ansible-install-pkg /opt/yunion/ansible-install-pkg
COPY --from=registry.cn-beijing.aliyuncs.com/yunionio/file-repo:v0.2.1 /opt/yunion/playbook /opt/yunion/playbook
COPY --from=registry.cn-beijing.aliyuncs.com/yunionio/file-repo:v0.2.1 /opt/yunion/ansible-install-pkg /opt/yunion/ansible-install-pkg
ADD ./_output/alpine-build/bin/ansibleserver /opt/yunion/bin/ansibleserver

View File

@@ -1,9 +1,11 @@
FROM registry.cn-beijing.aliyuncs.com/yunionio/baremetal-base:v0.2
FROM registry.cn-beijing.aliyuncs.com/yunionio/baremetal-base:v0.3.1
MAINTAINER "Zexi Li <lizexi@yunionyun.com>"
RUN mkdir -p /opt/yunion/bin
ADD ./_output/bin/baremetal-agent /opt/yunion/bin/baremetal-agent
ADD ./_output/bin/.baremetal-agent.bin /opt/yunion/bin/.baremetal-agent.bin
ADD ./_output/bin/bundles/baremetal-agent /opt/yunion/bin/bundles/baremetal-agent
#ADD ./_output/bin/baremetal-agent /opt/yunion/bin/baremetal-agent
#ADD ./_output/bin/.baremetal-agent.bin /opt/yunion/bin/.baremetal-agent.bin
#ADD ./_output/bin/bundles/baremetal-agent /opt/yunion/bin/bundles/baremetal-agent
RUN apk add librados librbd
ADD ./_output/alpine-build/bin/baremetal-agent /opt/yunion/bin/baremetal-agent

View File

@@ -1,7 +1,7 @@
FROM registry.cn-beijing.aliyuncs.com/yunionio/centos-build:1.1-4 as build
RUN yum install -y https://iso.yunion.cn/3.6/rpms/packages/host/baremetal-pxerom-1.1.0-20072810.x86_64.rpm
FROM --platform=linux/amd64 registry.cn-beijing.aliyuncs.com/yunionio/centos-build:1.1-4 as build
RUN yum install -y https://iso.yunion.cn/vm-images/baremetal-pxerom-1.1.0-21060506.x86_64.rpm
FROM frolvlad/alpine-glibc:glibc-2.28
FROM registry.cn-beijing.aliyuncs.com/yunionio/onecloud-base:v0.2
MAINTAINER "Yaoqi Wan <wanyaoqi@yunionyun.com>"

View File

@@ -1,4 +1,4 @@
FROM registry.cn-beijing.aliyuncs.com/yunionio/climc-base:20210508
FROM registry.cn-beijing.aliyuncs.com/yunionio/climc-base:20210701
ADD ./build/climc/root/opt /opt

View File

@@ -11,11 +11,10 @@ RUN set -x \
# install default playbook and install pkg
Run mkdir -p /opt/yunion/ansible-install-pkg
Run wget https://dl.influxdata.com/telegraf/releases/telegraf-1.17.0-1.x86_64.rpm -P /opt/yunion/ansible-install-pkg
Run wget https://dl.influxdata.com/telegraf/releases/telegraf-1.17.0-1.aarch64.rpm -P /opt/yunion/ansible-install-pkg
Run wget https://dl.influxdata.com/telegraf/releases/telegraf-1.17.0_windows_amd64.zip -P /opt/yunion/ansible-install-pkg
Run wget https://dl.influxdata.com/telegraf/releases/telegraf_1.17.0-1_amd64.deb -P /opt/yunion/ansible-install-pkg
Run wget https://dl.influxdata.com/telegraf/releases/telegraf_1.17.0-1_arm64.deb -P /opt/yunion/ansible-install-pkg
Run wget https://yunioniso.oss-cn-beijing.aliyuncs.com/rpms/telegraf/telegraf-1.5.0~yn-1.aarch64.rpm -P /opt/yunion/ansible-install-pkg
Run wget https://yunioniso.oss-cn-beijing.aliyuncs.com/rpms/telegraf/telegraf-1.5.0~yn-1.x86_64.rpm -P /opt/yunion/ansible-install-pkg
Run wget https://yunioniso.oss-cn-beijing.aliyuncs.com/rpms/telegraf/telegraf_1.5.0~yn-1_amd64.deb -P /opt/yunion/ansible-install-pkg
Run wget https://yunioniso.oss-cn-beijing.aliyuncs.com/rpms/telegraf/telegraf_1.5.0~yn-1_arm64.deb -P /opt/yunion/ansible-install-pkg
Run mkdir -p /opt/yunion/playbook
Run mkdir /opt/yunion/playbook/monitor-agent

View File

@@ -1,7 +1,20 @@
REGISTRY ?= "registry.cn-beijing.aliyuncs.com/yunionio"
DOCKER_BUILD = docker build -t $(REGISTRY)
DOCKER_BUILDX = docker buildx build --platform linux/arm64,linux/amd64 --push -t $(REGISTRY)
debian10-base:
docker buildx build --platform linux/arm64,linux/amd64 --push \
-t registry.cn-beijing.aliyuncs.com/yunionio/debian10-base:1.0 -f ./Dockerfile.debian-base .
CLIMC_BASE_VERSION = 20210701
climc-base:
docker buildx build --platform linux/arm64,linux/amd64 --push \
-t registry.cn-beijing.aliyuncs.com/yunionio/climc-base:$(VERSION) -f ./Dockerfile.climc-base .
-t registry.cn-beijing.aliyuncs.com/yunionio/climc-base:$(CLIMC_BASE_VERSION) -f ./Dockerfile.climc-base .
BAREMETAL_BASE_VERSION = v0.3.1
baremetal-base:
$(DOCKER_BUILDX)/baremetal-base:$(BAREMETAL_BASE_VERSION) -f ./Dockerfile.baremetal-base .
#docker push $(REGISTRY)/baremetal-base:$(BAREMETAL_BASE_VERSION)

View File

@@ -18,251 +18,38 @@ import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.Cloudproviders).WithKeyword("cloud-provider")
cmd.List(&compute.CloudproviderListOptions{})
cmd.Update(&compute.CloudproviderUpdateOptions{})
cmd.Show(&options.BaseIdOptions{})
cmd.Delete(&options.BaseIdOptions{})
cmd.Perform("change-project", &compute.CloudproviderChangeProjectOptions{})
cmd.Perform("enable", &options.BaseIdOptions{})
cmd.Perform("disable", &options.BaseIdOptions{})
cmd.Perform("sync", &compute.CloudproviderSyncOptions{})
cmd.Perform("project-mapping", &compute.ClouproviderProjectMappingOptions{})
type CloudproviderListOptions struct {
options.BaseListOptions
Usable bool `help:"Vpc & Network usable"`
HasObjectStorage bool `help:"filter cloudproviders that has object storage"`
NoObjectStorage bool `help:"filter cloudproviders that has no object storage"`
Capability []string `help:"capability filter" choices:"project|compute|network|loadbalancer|objectstore|rds|cache|event"`
Cloudregion string `help:"filter cloudproviders by cloudregion"`
HostSchedtagId string `help:"filter by host schedtag"`
}
R(&CloudproviderListOptions{}, "cloud-provider-list", "List cloud providers", func(s *mcclient.ClientSession, args *CloudproviderListOptions) error {
var params *jsonutils.JSONDict
{
var err error
params, err = args.BaseListOptions.Params()
if err != nil {
return err
}
if args.Usable {
params.Add(jsonutils.NewBool(true), "usable")
}
if args.HasObjectStorage {
params.Add(jsonutils.JSONTrue, "has_object_storage")
} else if args.NoObjectStorage {
params.Add(jsonutils.JSONFalse, "has_object_storage")
}
if len(args.Capability) > 0 {
params.Add(jsonutils.NewStringArray(args.Capability), "capability")
}
if len(args.Cloudregion) > 0 {
params.Add(jsonutils.NewString(args.Cloudregion), "cloudregion")
}
if len(args.HostSchedtagId) > 0 {
params.Add(jsonutils.NewString(args.HostSchedtagId), "host_schedtag_id")
}
}
result, err := modules.Cloudproviders.List(s, params)
if err != nil {
return err
}
printList(result, modules.Cloudproviders.GetColumns(s))
return nil
})
type CloudproviderUpdateOptions struct {
ID string `help:"ID or Name of cloud provider"`
Name string `help:"New name to update"`
AccessUrl string `help:"New access url"`
Desc string `help:"Description"`
}
R(&CloudproviderUpdateOptions{}, "cloud-provider-update", "Update a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderUpdateOptions) error {
params := jsonutils.NewDict()
if len(args.Name) > 0 {
params.Add(jsonutils.NewString(args.Name), "name")
}
if len(args.AccessUrl) > 0 {
params.Add(jsonutils.NewString(args.AccessUrl), "access_url")
}
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
}
if params.Size() == 0 {
return InvalidUpdateError()
}
result, err := modules.Cloudproviders.Update(s, args.ID, params)
if err != nil {
return err
}
printObject(result)
return nil
})
type CloudproviderChangeProjectOptions struct {
ID string `help:"ID or Name of cloud provider"`
TENANT string `help:"ID or Name of tenant"`
}
R(&CloudproviderChangeProjectOptions{}, "cloud-provider-change-project", "Change project for provider", func(s *mcclient.ClientSession, args *CloudproviderChangeProjectOptions) error {
result, err := modules.Cloudproviders.PerformAction(s, args.ID, "change-project", jsonutils.Marshal(map[string]string{"project": args.TENANT}))
if err != nil {
return err
}
printObject(result)
return nil
})
type CloudproviderShowOptions struct {
ID string `help:"ID or Name of cloud provider"`
}
R(&CloudproviderShowOptions{}, "cloud-provider-show", "Get details of a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error {
result, err := modules.Cloudproviders.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&CloudproviderShowOptions{}, "cloud-provider-delete", "Delete a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error {
result, err := modules.Cloudproviders.Delete(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&CloudproviderShowOptions{}, "cloud-provider-enable", "Enable cloud provider", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error {
result, err := modules.Cloudproviders.PerformAction(s, args.ID, "enable", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&CloudproviderShowOptions{}, "cloud-provider-disable", "Disable cloud provider", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error {
result, err := modules.Cloudproviders.PerformAction(s, args.ID, "disable", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&CloudproviderShowOptions{}, "cloud-provider-balance", "Get balance", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error {
result, err := modules.Cloudproviders.GetSpecific(s, args.ID, "balance", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type CloudproviderUpdateCredentialOptions struct {
ID string `help:"ID or Name of cloud provider"`
ACCOUNT string `help:"new account"`
SECRET string `help:"new secret"`
}
R(&CloudproviderUpdateCredentialOptions{}, "cloud-provider-update-credential", "Update credential of a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderUpdateCredentialOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.ACCOUNT), "account")
params.Add(jsonutils.NewString(args.SECRET), "secret")
result, err := modules.Cloudproviders.PerformAction(s, args.ID, "update-credential", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type CloudproviderSyncOptions struct {
ID string `help:"ID or Name of cloud provider"`
Force bool `help:"Force sync no matter what"`
FullSync bool `help:"Synchronize everything"`
ProjectSync bool `help:"Auto sync project info"`
Region []string `help:"region to sync"`
Zone []string `help:"region to sync"`
Host []string `help:"region to sync"`
}
R(&CloudproviderSyncOptions{}, "cloud-provider-sync", "Sync of a cloud provider account", func(s *mcclient.ClientSession, args *CloudproviderSyncOptions) error {
params := jsonutils.NewDict()
if args.Force {
params.Add(jsonutils.JSONTrue, "force")
}
if args.FullSync {
params.Add(jsonutils.JSONTrue, "full_sync")
}
if args.ProjectSync {
params.Add(jsonutils.JSONTrue, "project_sync")
}
if len(args.Region) > 0 {
params.Add(jsonutils.NewStringArray(args.Region), "region")
}
if len(args.Zone) > 0 {
params.Add(jsonutils.NewStringArray(args.Zone), "zone")
}
if len(args.Host) > 0 {
params.Add(jsonutils.NewStringArray(args.Host), "host")
}
result, err := modules.Cloudproviders.PerformAction(s, args.ID, "sync", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type CloudproviderClientRCOptions struct {
ID string `help:"ID or name of cloud provider"`
}
R(&CloudproviderClientRCOptions{}, "cloud-provider-clirc", "Get client RC file of the cloud provider", func(s *mcclient.ClientSession, args *CloudproviderClientRCOptions) error {
result, err := modules.Cloudproviders.GetSpecific(s, args.ID, "clirc", nil)
if err != nil {
return err
}
cmd.GetWithCustomShow("clirc", func(result jsonutils.JSONObject) {
rc := make(map[string]string)
err = result.Unmarshal(&rc)
err := result.Unmarshal(&rc)
if err != nil {
return err
log.Errorf("error: %v", err)
return
}
for k, v := range rc {
fmt.Printf(`export %s="%s"`+"\n", k, v)
}
return nil
})
type CloudproviderStorageClassesOptions struct {
ID string `help:"ID or Name of cloud provider" json:"-"`
Cloudregion string `help:"cloud region name or Id"`
}
R(&CloudproviderStorageClassesOptions{}, "cloud-provider-storage-classes", "Get list of supported storage classes of a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderStorageClassesOptions) error {
params, err := options.StructToParams(args)
if err != nil {
return err
}
result, err := modules.Cloudproviders.GetSpecific(s, args.ID, "storage-classes", params)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&CloudproviderShowOptions{}, "cloud-provider-change-owner-candidate-domains", "Show candiate domains of a cloud provider changing owner", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error {
result, err := modules.Cloudproviders.GetSpecific(s, args.ID, "change-owner-candidate-domains", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}, &options.BaseIdOptions{})
cmd.Get("storage-classes", &compute.CloudproviderStorageClassesOptions{})
cmd.Get("change-owner-candidate-domains", &options.BaseIdOptions{})
cmd.Get("balance", &options.BaseIdOptions{})
}

View File

@@ -20,159 +20,43 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/ssh"
)
func init() {
type HostListOptions struct {
Schedtag string `help:"List hosts in schedtag"`
Zone string `help:"List hosts in zone"`
Region string `help:"List hosts in region"`
Wire string `help:"List hosts in wire"`
Image string `help:"List hosts cached images" json:"cachedimage"`
Storage string `help:"List hosts attached to storages"`
Baremetal string `help:"List hosts that is managed by baremetal system" choices:"true|false"`
Empty bool `help:"show empty host" json:"-"`
Occupied bool `help:"show occupid host" json:"-"`
Enabled bool `help:"Show enabled host only" json:"-"`
Disabled bool `help:"Show disabled host only" json:"-"`
HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv|aliyun|azure|qcloud|aws|huawei|ucloud|google|ctyun"`
AnyMac string `help:"Mac matches one of the host's interface"`
AnyIp string `help:"IP matches one of the host's interface"`
cmd := shell.NewResourceCmd(&modules.Hosts)
cmd.List(&compute.HostListOptions{})
cmd.Show(&options.BaseShowOptions{})
cmd.GetMetadata(&options.BaseIdOptions{})
cmd.GetProperty(&compute.HostStatusStatisticsOptions{})
IsBaremetal *bool `help:"filter host list by is_baremetal=true|false"`
cmd.Perform("ping", &options.BaseIdOptions{})
cmd.Perform("undo-convert", &options.BaseIdOptions{})
cmd.Perform("maintenance", &options.BaseIdOptions{})
cmd.Perform("unmaintenance", &options.BaseIdOptions{})
cmd.Perform("start", &options.BaseIdOptions{})
cmd.Perform("stop", &options.BaseIdOptions{})
cmd.Perform("reset", &options.BaseIdOptions{})
cmd.Perform("delete", &options.BaseIdOptions{})
cmd.Perform("remove-all-netifs", &options.BaseIdOptions{})
ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"`
cmd.BatchPerform("enable", &options.BaseIdsOptions{})
cmd.BatchPerform("disable", &options.BaseIdsOptions{})
cmd.BatchPerform("syncstatus", &options.BaseIdsOptions{})
cmd.BatchPerform("sync-config", &options.BaseIdsOptions{})
cmd.BatchPerform("prepare", &options.BaseIdsOptions{})
cmd.BatchPerform("ipmi-probe", &options.BaseIdsOptions{})
Usable *bool `help:"List all zones that is usable"`
cmd.Get("ipmi", &options.BaseIdOptions{})
cmd.Get("vnc", &options.BaseIdOptions{})
Hypervisor string `help:"filter hosts by hypervisor"`
StorageNotAttached bool `help:"List hosts not attach specified storage"`
Uuid string `help:"find host with given system uuid"`
CdromBoot *bool `help:"filter hosts list by cdrom_boot=true|false"`
Sn string `help:"find host by sn"`
OrderByServerCount string `help:"Order by server count" choices:"desc|asc"`
options.BaseListOptions
}
R(&HostListOptions{}, "host-list", "List hosts", func(s *mcclient.ClientSession, opts *HostListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
if opts.Empty {
params.Add(jsonutils.JSONTrue, "is_empty")
} else if opts.Occupied {
params.Add(jsonutils.JSONFalse, "is_empty")
}
if opts.Enabled {
params.Add(jsonutils.NewInt(1), "enabled")
} else if opts.Disabled {
params.Add(jsonutils.NewInt(0), "enabled")
}
if len(opts.Uuid) > 0 {
params.Add(jsonutils.NewString(opts.Uuid), "uuid")
}
if len(opts.Sn) > 0 {
params.Add(jsonutils.NewString(opts.Sn), "sn")
}
result, err := modules.Hosts.List(s, params)
if err != nil {
return err
}
printList(result, modules.Hosts.GetColumns(s))
return nil
})
type HostDetailOptions struct {
ID string `help:"ID or name of host"`
}
R(&HostDetailOptions{}, "host-show", "Show details of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-ping", "Ping a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "ping", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-metadata", "Show metadata of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.GetMetadata(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type HostOpsOptions struct {
ID []string `help:"ID or name of hosts"`
}
R(&HostOpsOptions{}, "host-enable", "Enable a host", func(s *mcclient.ClientSession, args *HostOpsOptions) error {
results := modules.Hosts.BatchPerformAction(s, args.ID, "enable", nil)
printBatchResults(results, modules.Hosts.GetColumns(s))
return nil
})
R(&HostOpsOptions{}, "host-disable", "Disable a host", func(s *mcclient.ClientSession, args *HostOpsOptions) error {
results := modules.Hosts.BatchPerformAction(s, args.ID, "disable", nil)
printBatchResults(results, modules.Hosts.GetColumns(s))
return nil
})
R(&HostOpsOptions{}, "host-syncstatus", "Synchronize status of a host", func(s *mcclient.ClientSession, args *HostOpsOptions) error {
results := modules.Hosts.BatchPerformAction(s, args.ID, "syncstatus", nil)
printBatchResults(results, modules.Hosts.GetColumns(s))
return nil
})
R(&HostOpsOptions{}, "host-sync-config", "Synchronize config of a host", func(s *mcclient.ClientSession, args *HostOpsOptions) error {
results := modules.Hosts.BatchPerformAction(s, args.ID, "sync-config", nil)
printBatchResults(results, modules.Hosts.GetColumns(s))
return nil
})
R(&HostOpsOptions{}, "host-prepare", "Prepare a host for installation", func(s *mcclient.ClientSession, args *HostOpsOptions) error {
results := modules.Hosts.BatchPerformAction(s, args.ID, "prepare", nil)
printBatchResults(results, modules.Hosts.GetColumns(s))
return nil
})
R(&HostOpsOptions{}, "host-ipmi-probe", "Do ipmi probe host", func(s *mcclient.ClientSession, args *HostOpsOptions) error {
results := modules.Hosts.BatchPerformAction(s, args.ID, "ipmi-probe", nil)
printBatchResults(results, modules.Hosts.GetColumns(s))
return nil
})
R(&HostDetailOptions{}, "host-ipmi", "Get IPMI information of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.GetSpecific(s, args.ID, "ipmi", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-logininfo", "Get SSH login information of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
R(&options.BaseIdOptions{}, "host-logininfo", "Get SSH login information of a host", func(s *mcclient.ClientSession, args *options.BaseIdOptions) error {
srvid, e := modules.Hosts.GetId(s, args.ID, nil)
if e != nil {
return e
@@ -185,15 +69,6 @@ func init() {
return nil
})
R(&HostDetailOptions{}, "host-vnc", "Get VNC information of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.GetSpecific(s, args.ID, "vnc", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type HostPropertyOptions struct {
}
@@ -206,7 +81,7 @@ func init() {
return nil
})
R(&HostListOptions{}, "host-node-count", "Get host node count", func(s *mcclient.ClientSession, opts *HostListOptions) error {
R(&compute.HostListOptions{}, "host-node-count", "Get host node count", func(s *mcclient.ClientSession, opts *compute.HostListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
@@ -348,67 +223,6 @@ func init() {
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-undo-convert", "Undo converting a host to hypervisor", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "undo-convert", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-maintenance", "Reboot host into PXE offline OS, do maintenance jobs", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "maintenance", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-unmaintenance", "Reboot host back into disk installed OS", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "unmaintenance", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-start", "Power on host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "start", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-stop", "Power off host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "stop", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostDetailOptions{}, "host-reset", "Power reset host", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "reset", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&HostOpsOptions{}, "host-delete", "Delete host record", func(s *mcclient.ClientSession, args *HostOpsOptions) error {
results := modules.Hosts.BatchDelete(s, args.ID, nil)
printBatchResults(results, modules.Hosts.GetColumns(s))
return nil
})
type HostAddNetIfOptions struct {
ID string `help:"ID or Name of host"`
WIRE string `help:"ID or Name of wire to attach"`
@@ -506,15 +320,6 @@ func init() {
return nil
})
R(&HostDetailOptions{}, "host-remove-all-netifs", "Remvoe all netifs expect admin&ipmi netifs", func(s *mcclient.ClientSession, args *HostDetailOptions) error {
result, err := modules.Hosts.PerformAction(s, args.ID, "remove-all-netifs", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type HostCacheImageActionOptions struct {
ID string `help:"ID or name of host"`
IMAGE string `help:"ID or name of image"`

View File

@@ -87,6 +87,7 @@ func init() {
cmd.Perform("remote-update", new(options.ServerRemoteUpdateOptions))
cmd.Perform("create-eip", &options.ServerCreateEipOptions{})
cmd.Perform("make-sshable", &options.ServerMakeSshableOptions{})
cmd.Perform("migrate-network", &options.ServerMigrateNetworkOptions{})
cmd.Get("vnc", new(options.ServerIdOptions))
cmd.Get("desc", new(options.ServerIdOptions))
@@ -96,6 +97,8 @@ func init() {
cmd.Get("sshable", new(options.ServerIdOptions))
cmd.Get("make-sshable-cmd", new(options.ServerIdOptions))
cmd.Get("change-owner-candidate-domains", new(options.ServerChangeOwnerCandidateDomainsOptions))
cmd.Get("change-owner-candidate-domains", new(options.ServerChangeOwnerCandidateDomainsOptions))
cmd.GetProperty(&options.ServerStatusStatisticsOptions{})
type ServerTaskShowOptions struct {
ID string `help:"ID or name of server" json:"-"`
@@ -179,6 +182,19 @@ func init() {
return nil
})
R(&options.ResourceMetadataOptions{}, "server-set-metadata", "Set raw metadata of a server", func(s *mcclient.ClientSession, opts *options.ResourceMetadataOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
result, err := modules.Servers.PerformAction(s, opts.ID, "metadata", params)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&options.ServerCreateFromInstanceSnapshot{}, "server-create-from-instance-snapshot", "server create from instance snapshot",
func(s *mcclient.ClientSession, opts *options.ServerCreateFromInstanceSnapshot) error {
params := &compute.ServerCreateInput{}

View File

@@ -224,6 +224,28 @@ type IShowOpt interface {
IIdOpt
}
type IPropertyOpt interface {
IOpt
Property() string
}
func (cmd ResourceCmd) GetProperty(args IPropertyOpt) {
man := cmd.manager
callback := func(s *mcclient.ClientSession, args IPropertyOpt) error {
params, err := args.Params()
if err != nil {
return err
}
ret, err := man.(modulebase.Manager).Get(s, args.Property(), params)
if err != nil {
return err
}
printObject(ret)
return nil
}
cmd.RunWithDesc(args.Property(), fmt.Sprintf("Get property of a %s", man.GetKeyword()), args, callback)
}
func (cmd ResourceCmd) Show(args IShowOpt) {
man := cmd.manager
callback := func(s *mcclient.ClientSession, args IShowOpt) error {
@@ -421,7 +443,7 @@ type IGetOpt interface {
IOpt
}
func (cmd ResourceCmd) Get(specific string, args IGetOpt) {
func (cmd ResourceCmd) GetWithCustomShow(specific string, show func(data jsonutils.JSONObject), args IGetOpt) {
man := cmd.manager
callback := func(s *mcclient.ClientSession, args IGetOpt) error {
params, err := args.Params()
@@ -432,12 +454,16 @@ func (cmd ResourceCmd) Get(specific string, args IGetOpt) {
if err != nil {
return err
}
printObject(ret)
show(ret)
return nil
}
cmd.RunWithDesc(specific, fmt.Sprintf("Get %s of a %s", specific, man.GetKeyword()), args, callback)
}
func (cmd ResourceCmd) Get(specific string, args IGetOpt) {
cmd.GetWithCustomShow(specific, printObject, args)
}
type IUpdateOpt interface {
IOpt
IIdOpt

View File

@@ -24,13 +24,14 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/cmd/climc/shell"
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/identity"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/shellutils"
@@ -74,25 +75,8 @@ func createPolicy(s *mcclient.ClientSession, name string, policy string, domain
}
func init() {
type PolicyListOptions struct {
options.BaseListOptions
Type string `help:"filter by type"`
IsSystem *bool `help:"filter by is_system" negative:"is_no_system"`
Format string `help:"policy format, default to yaml" default:"yaml" choices:"yaml|json"`
OrderByDomain string `help:"order by domain name" choices:"asc|desc"`
}
R(&PolicyListOptions{}, "policy-list", "List all policies", func(s *mcclient.ClientSession, args *PolicyListOptions) error {
params, err := options.ListStructToParams(args)
if err != nil {
return err
}
result, err := modules.Policies.List(s, params)
if err != nil {
return err
}
printList(result, modules.Policies.GetColumns(s))
return nil
})
cmd := shell.NewResourceCmd(&modules.Policies)
cmd.List(&identity.PolicyListOptions{})
type PolicyCreateOptions struct {
Domain string `help:"domain of the policy"`

View File

@@ -17,100 +17,21 @@ package identity
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/identity"
)
func init() {
type RoleListOptions struct {
options.BaseListOptions
OrderByDomain string `help:"order by domain name" choices:"asc|desc"`
}
R(&RoleListOptions{}, "role-list", "List keystone Roles", func(s *mcclient.ClientSession, args *RoleListOptions) error {
params, err := options.ListStructToParams(args)
if err != nil {
return err
}
result, err := modules.RolesV3.List(s, params)
if err != nil {
return err
}
printList(result, modules.RolesV3.GetColumns(s))
return nil
})
type RoleDetailOptions struct {
ID string `help:"ID or name of role"`
Domain string `help:"Domain"`
}
R(&RoleDetailOptions{}, "role-show", "Show details of a role", func(s *mcclient.ClientSession, args *RoleDetailOptions) error {
query := jsonutils.NewDict()
if len(args.Domain) > 0 {
domainId, err := modules.Domains.GetId(s, args.Domain, nil)
if err != nil {
return err
}
query.Add(jsonutils.NewString(domainId), "domain_id")
}
role, err := modules.RolesV3.Get(s, args.ID, query)
if err != nil {
return err
}
printObject(role)
return nil
})
R(&RoleDetailOptions{}, "role-delete", "Delete a role", func(s *mcclient.ClientSession, args *RoleDetailOptions) error {
query := jsonutils.NewDict()
if len(args.Domain) > 0 {
domainId, err := modules.Domains.GetId(s, args.Domain, nil)
if err != nil {
return err
}
query.Add(jsonutils.NewString(domainId), "domain_id")
}
rid, err := modules.RolesV3.GetId(s, args.ID, query)
if err != nil {
return err
}
role, err := modules.RolesV3.Delete(s, rid, nil)
if err != nil {
return err
}
printObject(role)
return nil
})
type RoleCreateOptions struct {
NAME string `help:"Role name"`
Domain string `help:"Domain"`
Desc string `help:"Description"`
PublicScope string `help:"public scope" choices:"none|system"`
}
R(&RoleCreateOptions{}, "role-create", "Create a new role", func(s *mcclient.ClientSession, args *RoleCreateOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.NAME), "name")
if len(args.Domain) > 0 {
domainId, err := modules.Domains.GetId(s, args.Domain, nil)
if err != nil {
return err
}
params.Add(jsonutils.NewString(domainId), "domain_id")
}
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
}
if len(args.PublicScope) > 0 {
params.Add(jsonutils.NewString(args.PublicScope), "public_scope")
}
role, err := modules.RolesV3.Create(s, params)
if err != nil {
return err
}
printObject(role)
return nil
})
cmd := shell.NewResourceCmd(&modules.RolesV3)
cmd.List(&identity.RoleListOptions{})
cmd.Show(&identity.RoleDetailOptions{})
cmd.Delete(&identity.RoleDetailOptions{})
cmd.Create(&identity.RoleCreateOptions{})
cmd.Perform("public", &options.BaseIdOptions{})
cmd.Perform("private", &options.BaseIdOptions{})
type RoleUpdateOptions struct {
ID string `help:"Role ID or Name"`
@@ -145,25 +66,4 @@ func init() {
printObject(role)
return nil
})
type RolePerformOptions struct {
ID string `help:"ID of role to update"`
}
R(&RolePerformOptions{}, "role-public", "Mark a role public", func(s *mcclient.ClientSession, args *RolePerformOptions) error {
result, err := modules.RolesV3.PerformAction(s, args.ID, "public", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&RolePerformOptions{}, "role-private", "Mark a role private", func(s *mcclient.ClientSession, args *RolePerformOptions) error {
result, err := modules.RolesV3.PerformAction(s, args.ID, "private", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}

View File

@@ -24,6 +24,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules/k8s"
o "yunion.io/x/onecloud/pkg/mcclient/options/k8s"
@@ -201,18 +202,32 @@ func initKubeCluster() {
return nil
})
R(&o.ClusterEnableComponentMinioOpt{}, cmdN("component-enable-minio"), "Enable cluster minio component", func(s *mcclient.ClientSession, args *o.ClusterEnableComponentMinioOpt) error {
params, err := args.Params()
if err != nil {
return err
}
ret, err := k8s.KubeClusters.PerformAction(s, args.ID, "enable-component", params)
if err != nil {
return err
}
printObject(ret)
return nil
})
rEnableMinio := func(opt shell.IPerformOpt, cmd string, desc string) {
R(opt, cmd, desc, func(s *mcclient.ClientSession, args shell.IPerformOpt) error {
params, err := args.Params()
if err != nil {
return err
}
ret, err := k8s.KubeClusters.PerformAction(s, args.GetId(), "enable-component", params)
if err != nil {
return err
}
printObject(ret)
return nil
})
}
rEnableMinio(
new(o.ClusterEnableComponentMinioOpt),
cmdN("component-enable-minio"),
"Enable cluster minio component",
)
rEnableMinio(
new(o.ClusterEnableComponentMonitorMinioOpt),
cmdN("component-enable-monitor-minio"),
"Enable cluster monitor stack's minio component",
)
R(&o.ClusterEnableComponentThanosOpt{}, cmdN("component-enable-thanos"), "Enable cluster thanos component", func(s *mcclient.ClientSession, args *o.ClusterEnableComponentThanosOpt) error {
params, err := args.Params()
@@ -260,9 +275,14 @@ func initKubeCluster() {
return nil
})
R(&o.ClusterComponentType{}, cmdN("component-update"), "Update cluster component", func(s *mcclient.ClientSession, args *o.ClusterComponentType) error {
type ClusterComponentTypeUpdate struct {
o.ClusterComponentType
Force bool `help:"Force update"`
}
R(&ClusterComponentTypeUpdate{}, cmdN("component-update"), "Update cluster component", func(s *mcclient.ClientSession, args *ClusterComponentTypeUpdate) error {
// 1. get current setting
setting, err := getComponentSetting(s, args, false)
setting, err := getComponentSetting(s, &args.ClusterComponentType, false)
if err != nil {
return errors.Wrap(err, "get component setting")
}
@@ -270,8 +290,11 @@ func initKubeCluster() {
// 2. edit yaml
yaml, err := shellutils.Edit(setting.YAMLString())
if len(yaml) == 0 {
log.Infof("Nothing to update")
return nil
if !args.Force {
log.Infof("Nothing to update")
return nil
}
yaml = setting.YAMLString()
}
nowSetting, err := jsonutils.ParseYAML(yaml)
if err != nil {
@@ -279,6 +302,7 @@ func initKubeCluster() {
}
params := args.Params(args.TYPE)
params.Update(nowSetting)
params.Add(jsonutils.NewBool(args.Force), "force")
// 3. call update api
ret, err := k8s.KubeClusters.PerformAction(s, args.ID, "update-component", params)

View File

@@ -0,0 +1,20 @@
package meter
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
options "yunion.io/x/onecloud/pkg/mcclient/options/meter"
)
func init() {
cmd := shell.NewResourceCmd(modules.BillingDimensionManager)
cmd.Create(&options.BillDimensionCreateOptions{})
cmd.List(&options.BillDimensionListOptions{})
cmd.Show(&options.BillDimensionShowOptions{})
cmd.Delete(&options.BillDimensionDeleteOptions{})
cmdAnalysis := shell.NewResourceCmd(modules.BillingDimensionAnalysisManager)
cmdAnalysis.List(&options.BillDimensionAnalysisListOptions{})
cmdAnalysis.Show(&options.BillDimensionAnalysisShowOptions{})
}

View File

@@ -0,0 +1,29 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package meter
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
options "yunion.io/x/onecloud/pkg/mcclient/options/meter"
)
func init() {
cmd := shell.NewResourceCmd(&modules.CostConversions).WithKeyword("cost-conversion")
cmd.List(new(options.CostConversionListOptions))
cmd.Create(new(options.CostConversionCreateOptions))
cmd.Update(new(options.CostConversionUpdateOptions))
cmd.Delete(new(options.CostConversionDeleteOptions))
}

View File

@@ -17,6 +17,11 @@ package misc
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
@@ -35,6 +40,43 @@ func init() {
return nil
})
type VersionListOptions struct {
}
R(&VersionListOptions{}, "version-list", "query all backend service version", func(s *mcclient.ClientSession, args *VersionListOptions) error {
services := []jsonutils.JSONObject{}
params := map[string]interface{}{}
for {
params["offset"] = len(services)
resp, err := modules.ServicesV3.List(s, jsonutils.Marshal(params))
if err != nil {
return err
}
services = append(services, resp.Data...)
if len(services) >= resp.Total {
break
}
}
vers := map[string]string{}
for _, service := range services {
serviceType, _ := service.GetString("type")
if utils.IsInStringArray(serviceType, []string{"offlinecloudmeta"}) {
continue
}
ver, err := modules.GetVersion(s, serviceType)
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound || errors.Cause(err) == errors.ErrConnectRefused {
continue
}
vers[serviceType] = err.Error()
} else {
vers[serviceType] = ver
}
}
printObject(jsonutils.Marshal(vers))
return nil
})
R(&options.VersionListOptions{}, "yunionagent-version-list", "show versions of backend services", func(s *mcclient.ClientSession, opts *options.VersionListOptions) error {
if len(opts.Region) == 0 {
opts.Region = s.GetRegion()

View File

@@ -0,0 +1,13 @@
package monitor
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
options "yunion.io/x/onecloud/pkg/mcclient/options/monitor"
)
func init() {
cmd := shell.NewResourceCmd(modules.MonitorResourceManager)
cmd.Get("", new(options.MonitorResourceJointAlertOptions))
}

View File

@@ -15,12 +15,17 @@
package main
import (
"context"
"yunion.io/x/onecloud/pkg/util/atexit"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/webconsole/service"
)
func main() {
defer atexit.Handle()
go procutils.WaitZombieLoop(context.TODO())
service.StartService()
}

2
go.mod
View File

@@ -150,7 +150,7 @@ require (
yunion.io/x/jsonutils v0.0.0-20201110084044-3e4e1cb49769
yunion.io/x/log v0.0.0-20201210064738-43181789dc74
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
yunion.io/x/pkg v0.0.0-20210218105412-13a69f60034c
yunion.io/x/pkg v0.0.0-20210721081124-55078288ca4c
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
yunion.io/x/sqlchemy v0.0.0-20210401131841-cdb9ab689824
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce

4
go.sum
View File

@@ -924,8 +924,8 @@ yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7/go.mod h1:0vLkNEhlmA64HViPB
yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20200814072949-4f1b541857d6/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20210218105412-13a69f60034c h1:J/joqbA1N2mAlOl0Uqd4LpAq3+DK5aoFMdz+p9Ld7pQ=
yunion.io/x/pkg v0.0.0-20210218105412-13a69f60034c/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20210721081124-55078288ca4c h1:/ejlt78/0xod4bdkEThUuYsQ7vLajd48wpL2GMMSaXs=
yunion.io/x/pkg v0.0.0-20210721081124-55078288ca4c/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
yunion.io/x/sqlchemy v0.0.0-20210401131841-cdb9ab689824 h1:3/VcCiO+vr3+zZFLNvre41ARF2xE6NVq6Ue7JPFuJvU=

View File

@@ -138,26 +138,17 @@ func (ai *SAnsiblePlaybookInstance) runPlaybook(ctx context.Context, userCred mc
return errors.Wrap(err, "unable to update ansibleplaybookinstance")
}
convertJO := func(o jsonutils.JSONObject) map[string]interface{} {
if o == nil {
return map[string]interface{}{}
}
ret := make(map[string]interface{})
o.Unmarshal(&ret)
return ret
}
// merge configs
params := make(map[string]interface{})
for k, v := range convertJO(ar.DefaultParams) {
params[k] = v
}
for k, v := range convertJO(ai.Params) {
params[k] = v
dp, params := ar.DefaultParams.(*jsonutils.JSONDict), ai.Params.(*jsonutils.JSONDict)
for _, k := range dp.SortedKeys() {
v, _ := dp.Get(k)
params.Set(k, v)
}
ar.DefaultParams.(*jsonutils.JSONDict).SortedKeys()
sess := ansiblev2.NewOfflineSession().
Inventory(ai.Inventory).
PrivateKey(privateKey).
Configs(params).
ConfigYaml(params.YAMLString()).
PlaybookPath(ar.PlaybookPath).
OutputWriter(&ansiblePlaybookOutputWriter{ai}).
KeepTmpdir(options.Options.KeepTmpdir)

View File

@@ -116,7 +116,7 @@ func (h *AuthHandlers) getIdpSsoRedirectUri(ctx context.Context, w http.Response
}
func findExtUserId(input string) string {
pattern := regexp.MustCompile(`idp.SyncOrCreateDomainAndUser: ([^:]+): UserNotFoundError`)
pattern := regexp.MustCompile(`idp.SyncOrCreateDomainAndUser: ([^:]+): UserNotFound`)
matches := pattern.FindAllStringSubmatch(input, -1)
log.Debugf("%#v", matches)
if len(matches) > 0 && len(matches[0]) > 1 {

View File

@@ -22,7 +22,7 @@ func TestFindExtUserId(t *testing.T) {
want string
}{
{
in: "authUserByCASV3: Authenticate: idp.SyncOrCreateDomainAndUser: qiujian: UserNotFoundError",
in: "authUserByCASV3: Authenticate: idp.SyncOrCreateDomainAndUser: qiujian: UserNotFound",
want: "qiujian",
},
}

View File

@@ -22,6 +22,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -190,45 +191,62 @@ func (f *ResourceHandlers) listHandler(ctx context.Context, w http.ResponseWrite
func (f *ResourceHandlers) doList(ctx context.Context, session *mcclient.ClientSession, module modulebase.IBaseManager, query jsonutils.JSONObject, w http.ResponseWriter, r *http.Request) {
var exportKeys []string
var exportTexts []string
exportFormat, _ := query.GetString("export")
if len(exportFormat) > 0 {
exportKeyStr, _ := query.GetString("export_keys")
exportTextStr, _ := query.GetString("export_texts")
if len(exportKeyStr) > 0 {
exportKeys = strings.Split(exportKeyStr, ",")
export := struct {
ExportFormat string `json:"export"`
ExportKeys string `json:"export_keys"`
ExportTexts string `json:"export_texts"`
}{}
query.Unmarshal(&export)
if len(export.ExportFormat) > 0 {
if len(export.ExportKeys) > 0 {
exportKeys = strings.Split(export.ExportKeys, ",")
}
if len(exportTextStr) > 0 {
exportTexts = strings.Split(exportTextStr, ",")
if len(export.ExportTexts) > 0 {
exportTexts = strings.Split(export.ExportTexts, ",")
}
if len(exportKeys) == 0 {
httperrors.InvalidInputError(ctx, w, "missing export keys")
return
} else if len(exportKeys) != len(exportTexts) {
if len(exportTexts) == 0 {
exportTexts = exportKeys
} else {
httperrors.InvalidInputError(ctx, w, "inconsistent export keys and texts")
return
}
}
if len(exportTexts) == 0 {
exportTexts = exportKeys
}
if len(exportKeys) != len(exportTexts) {
httperrors.InvalidInputError(ctx, w, "inconsistent export keys and texts")
return
}
queryDict := query.(*jsonutils.JSONDict)
queryDict.Remove("export")
queryDict.Remove("export_texts")
keys := []string{}
for _, key := range exportKeys {
if !strings.Contains(key, ".") {
keys = append(keys, key)
continue
}
key = strings.Split(key, ".")[0]
if !utils.IsInStringArray(key, keys) {
keys = append(keys, key)
}
}
queryDict.Set("export_keys", jsonutils.NewString(strings.Join(keys, ",")))
query = queryDict
}
ret, e := module.List(session, query)
if e != nil {
httperrors.GeneralServerError(ctx, w, e)
} else if len(exportFormat) > 0 {
return
}
if len(export.ExportFormat) > 0 {
w.Header().Set("Content-Description", "File Transfer")
w.Header().Set("Content-Transfer-Encoding", "binary")
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"export-%s.xlsx\"", module.KeyString()))
excelutils.Export(ret.Data, exportKeys, exportTexts, w)
} else {
appsrv.SendJSON(w, modulebase.ListResult2JSON(ret))
return
}
appsrv.SendJSON(w, modulebase.ListResult2JSON(ret))
}
// get single
@@ -787,7 +805,7 @@ func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWrit
jmod, e := modulebase.GetJointModule2(session, module, module2)
var obj jsonutils.JSONObject
if e == nil { // joint detach
obj, e = jmod.Detach(session, req.ResID(), req.ResID2(), nil)
obj, e = jmod.Detach(session, req.ResID(), req.ResID2(), req.Query())
} else {
obj, e = module2.DeleteInContextWithParam(session, req.ResID2(), req.Query(), req.Body(), module, req.ResID())
}

View File

@@ -137,6 +137,8 @@ type CloudproviderDetails struct {
// 子订阅品牌信息
Brand string `json:"brand"`
ProjectMappingResourceInfo
}
// 云订阅输入参数

View File

@@ -535,3 +535,10 @@ type ServerResizeDiskInput struct {
DiskResizeInput
}
type ServerMigrateNetworkInput struct {
// Source network Id
Src string `json:"src"`
// Destination network Id
Dest string `json:"dest"`
}

View File

@@ -153,6 +153,9 @@ type ProjectMappingDetails struct {
// 所绑定的云账号列表
Accounts []SProjectMappingAccount `json:"accounts"`
// 所绑定的云订阅列表
Managers []SProjectMappingAccount `json:"managers"`
}
type ProjectMappingCreateInput struct {

View File

@@ -19,13 +19,13 @@ import "yunion.io/x/onecloud/pkg/apis"
type SnapshotCreateInput struct {
apis.VirtualResourceCreateInput
// 磁盘名称或Id,建议使用Id
// 磁盘Id
// 目前仅VMware平台不支持创建快照,其余平台磁盘均支持创建快照
// required: true
Disk string `json:"disk"`
// swagger:ignore
DiskId string `json:"disk_id"`
// swagger:ignore
Disk string `json:"disk" yunion-deprecated-by:"disk_id"`
// swagger:ignore
StorageId string `json:"storage_id"`
// swagger:ignore
CreatedBy string `json:"created_by"`

View File

@@ -346,6 +346,12 @@ type PolicyListInput struct {
// 是否显示系统权限
IsSystem *bool `json:"is_system"`
// filter policies by role id
RoleId string `json:"role_id"`
// swagger: ignore
// Deprecated
Role string `json:"role" yunion-deprecated-by:"role_id"`
}
type RegionFilterListInput struct {

View File

@@ -4,6 +4,7 @@ import "yunion.io/x/onecloud/pkg/apis"
type AlertPanelCreateInput struct {
apis.ScopedResourceInput
apis.ProjectizedResourceListInput
CommonMetricInputQuery
AlertCreateInput

View File

@@ -40,6 +40,7 @@ var (
"brand": "brand",
"domain_id": "domain_id",
"project_domain": "project_domain",
"access_ip": "access_ip",
}
RdsTags = map[string]string{

View File

@@ -12,6 +12,7 @@ const (
METRIC_RES_TYPE_TENANT = "tenant"
METRIC_RES_TYPE_DOMAIN = "domain"
METRIC_RES_TYPE_STORAGE = "storage"
METRIC_RES_TYPE_JENKINS = "jenkins"
METRIC_UNIT_PERCENT = "%"
METRIC_UNIT_BPS = "bps"

View File

@@ -0,0 +1,38 @@
package monitor
import (
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/apis/compute"
)
const (
MONITOR_RESOURCE_ALERT_STATUS_INIT = "init"
MONITOR_RESOURCE_ALERT_STATUS_ATTACH = "attach"
MONITOR_RESOURCE_ALERT_STATUS_ALERTING = "alerting"
)
type MonitorResourceCreateInput struct {
apis.VirtualResourceCreateInput
apis.EnabledBaseResourceCreateInput
ResId string `json:"res_id"`
ResType string `json:"res_type"`
AlertStatus string `json:"alert_status"`
}
type MonitorResourceListInput struct {
apis.VirtualResourceListInput
apis.EnabledResourceBaseListInput
compute.ManagedResourceListInput
ResId []string `json:"res_id"`
ResType string `json:"res_type"`
OnlyResId bool `json:"only_res_id"`
}
type MonitorResourceDetails struct {
apis.VirtualResourceDetails
compute.CloudregionResourceInfo
AttachAlertCount int64 `json:"attach_alert_count"`
}

View File

@@ -0,0 +1,24 @@
package monitor
import (
"time"
"yunion.io/x/onecloud/pkg/apis"
)
type MonitorResourceJointListInput struct {
MonitorResourceId string `json:"monitor_resource_id"`
AlertId string `json:"alert_id"`
JointId []int64 `json:"joint_id"`
}
type MonitorResourceJointCreateInput struct {
apis.Meta
MonitorResourceId string `json:"monitor_resource_id"`
AlertId string `json:"alert_id"`
AlertRecordId string `width:"36" charset:"ascii" list:"user" update:"user"`
AlertState string `width:"18" charset:"ascii" list:"user" update:"user"`
TriggerTime time.Time `list:"user" update:"user" json:"trigger_time"`
Data EvalMatch `json:"data"`
}

View File

@@ -230,3 +230,11 @@ type OpsLogDetails struct {
OwnerDomain string `json:"owner_domain"`
OwnerProject string `json:"owner_tenant"`
}
type StatusStatistic struct {
// 资源总数
TotalCount int64 `json:"total_count"`
// 回收站数量
// 需要指定pending_delete=all
PendingDeletedCount int64 `json:"pending_deleted_count"`
}

View File

@@ -96,7 +96,7 @@ func (job *SStatusProbeJob) Do(ctx context.Context, now time.Time) error {
if bStatus == api.BAREMETAL_READY || bStatus == api.BAREMETAL_RUNNING || bStatus == api.BAREMETAL_UNKNOWN {
ps, err := job.baremetal.GetPowerStatus()
if err != nil {
return errors.Wrap(err, "GetPowerStatus")
return errors.Wrap(err, "StatusProbeJob get power status")
}
job.lastTime = now
pps := PowerStatusToBaremetalStatus(ps)

View File

@@ -212,9 +212,13 @@ func handleServerStart(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremet
}
func handleServerStop(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremetaltypes.IBaremetalServer) {
if err := bm.StartServerStopTask(ctx.UserCred(), ctx.TaskId(), ctx.Data()); err != nil {
ctx.ResponseError(httperrors.NewGeneralError(err))
return
if bm.HasBMC() {
if err := bm.StartServerStopTask(ctx.UserCred(), ctx.TaskId(), ctx.Data()); err != nil {
ctx.ResponseError(httperrors.NewGeneralError(err))
return
}
} else {
bm.StartBaremetalMaintenanceTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
}
ctx.ResponseOk()
}

View File

@@ -50,6 +50,7 @@ import (
"yunion.io/x/onecloud/pkg/baremetal/utils/disktool"
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
raiddrivers "yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
"yunion.io/x/onecloud/pkg/baremetal/utils/uefi"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/compute/baremetal"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
@@ -797,7 +798,11 @@ func PowerStatusToServerStatus(bm *SBaremetalInstance, status string) string {
if conf, _ := bm.GetSSHConfig(); conf == nil {
return baremetalstatus.SERVER_RUNNING
} else {
return baremetalstatus.SERVER_ADMIN
if !bm.HasBMC() && !bm.IsMaintenance() {
return baremetalstatus.SERVER_READY
} else {
return baremetalstatus.SERVER_ADMIN
}
}
case types.POWER_STATUS_OFF:
return baremetalstatus.SERVER_READY
@@ -927,13 +932,18 @@ func (b *SBaremetalInstance) NeedPXEBoot() bool {
taskNeedPXEBoot = true
}
ret := false
if taskNeedPXEBoot || (task == nil && len(serverId) == 0 && b.GetHostType() == "baremetal") {
if taskNeedPXEBoot || (task == nil && len(serverId) == 0 && b.GetHostType() == "baremetal") || (task == nil && b.IsMaintenance()) {
ret = true
}
log.Infof("Check task %s, server %s NeedPXEBoot: %v", taskName, serverId, ret)
return ret
}
func (b *SBaremetalInstance) IsMaintenance() bool {
isMt, _ := b.desc.Bool("is_maintenance")
return isMt
}
func (b *SBaremetalInstance) GetHostType() string {
hostType, _ := b.desc.GetString("host_type")
return hostType
@@ -990,6 +1000,13 @@ func (b *SBaremetalInstance) getDHCPConfig(
if err != nil {
return nil, err
}
if isPxe && IsUEFIPxeArch(arch) && !b.NeedPXEBoot() {
// TODO: use chainloader boot UEFI firmware,
// currently not response PXE request,
// and let BIOS detect bootable device
b.ClearSSHConfig()
return nil, errors.Errorf("Baremetal %s not need UEFI PXE boot", b.GetName())
}
return GetNicDHCPConfig(nic, serverIP.String(), hostName, isPxe, arch)
}
@@ -1290,6 +1307,19 @@ func (b *SBaremetalInstance) GetRawIPMIConfig() *types.SIPMIInfo {
return &ipmiInfo
}
func (b *SBaremetalInstance) GetUEFIInfo() (*types.EFIBootMgrInfo, error) {
key := "uefi_info"
if !b.desc.Contains(key) {
return nil, nil
}
info := new(types.EFIBootMgrInfo)
if err := b.desc.Unmarshal(info, key); err != nil {
return nil, errors.Wrap(err, "Unmarshal json")
}
return info, nil
}
func (b *SBaremetalInstance) GetAccessIp() string {
accessIp, _ := b.desc.GetString("access_ip")
return accessIp
@@ -1347,6 +1377,206 @@ func (b *SBaremetalInstance) SetExistingIPMIIPAddr(ipAddr string) {
b.desc.Set("ipmi_info", info)
}
func (b *SBaremetalInstance) HasBMC() bool {
conf := b.GetIPMIConfig()
if conf == nil {
return false
}
return true
}
func (b *SBaremetalInstance) GetHostSSHClient() (*ssh.Client, error) {
conf, err := b.GetSSHConfig()
if err != nil {
return nil, errors.Wrap(err, "Get host ssh config")
}
if conf == nil {
return nil, errors.Errorf("Host ssh config is empty")
}
sshCli, err := ssh.NewClient(conf.RemoteIP, 22, "root", conf.Password, "")
if err != nil {
return nil, errors.Wrap(err, "New ssh client")
}
return sshCli, nil
}
func (b *SBaremetalInstance) GetServerSSHClient() (*ssh.Client, error) {
s := b.GetServer()
if s == nil {
return nil, errors.Error("No server")
}
privateKey, err := modules.Sshkeypairs.FetchPrivateKey(context.TODO(), auth.AdminCredential())
if err != nil {
return nil, errors.Wrapf(err, "Get server %s login info", s.GetId())
}
nics := s.GetNics()
var errs []error
for _, nic := range nics {
if nic.LinkUp && nic.Ip != "" {
for _, user := range []string{"cloudroot", "root"} {
sshCli, err := ssh.NewClient(nic.Ip, 22, user, "", privateKey)
if err != nil {
err = errors.Wrapf(err, "New server %s ssh client %s@%s", s.GetName(), user, nic.Ip)
errs = append(errs, err)
} else {
return sshCli, nil
}
}
}
}
return nil, errors.NewAggregate(errs)
}
func (b *SBaremetalInstance) SSHReachable() (bool, error) {
var errs []error
if cli, err := b.GetHostSSHClient(); err != nil {
errs = append(errs, err)
} else {
// host ssh reachable
cli.Close()
return true, nil
}
if cli, err := b.GetServerSSHClient(); err != nil {
errs = append(errs, err)
} else {
// server ssh reachable
cli.Close()
return true, nil
}
return false, errors.NewAggregate(errs)
}
func (b *SBaremetalInstance) sshRunWrapper(
hostRun func(hostCli *ssh.Client) ([]string, error),
serverRun func(serverCli *ssh.Client) ([]string, error),
) ([]string, error) {
hostCli, err := b.GetHostSSHClient()
if err != nil {
log.Warningf("Get host ssh client error: %v", err)
} else {
if hostCli != nil {
return hostRun(hostCli)
}
}
serverCli, err := b.GetServerSSHClient()
if err != nil {
return nil, errors.Wrapf(err, "Get baremetal %s server ssh client", b.GetName())
}
return serverRun(serverCli)
}
func (b *SBaremetalInstance) sshRun(hostCmd string, serverCmd string) ([]string, error) {
return b.sshRunWrapper(
func(hostCli *ssh.Client) ([]string, error) {
return hostCli.RawRun(hostCmd)
},
func(serverCli *ssh.Client) ([]string, error) {
return serverCli.RunWithTTY(serverCmd)
},
)
}
func (b *SBaremetalInstance) adjustUEFIWrapper(cli *ssh.Client, f func() error) error {
isUEFI, err := uefi.RemoteIsUEFIBoot(cli)
if err != nil {
return errors.Wrap(err, "Check is uefi boot")
}
if !isUEFI {
return nil
}
return f()
}
func (b *SBaremetalInstance) AdjustUEFICurrentBootOrder(hostCli *ssh.Client) error {
return b.adjustUEFIWrapper(hostCli, func() error {
mgr, err := uefi.NewEFIBootMgrFromRemote(hostCli, false)
if err != nil {
return errors.Wrap(err, "NewEFIBootMgrFromRemote")
}
if err := uefi.RemoteSetCurrentBootAtFirst(hostCli, mgr); err != nil {
return errors.Wrap(err, "Set current boot order at first")
}
return b.SendUEFIInfo(mgr)
})
}
func (b *SBaremetalInstance) SendUEFIInfo(mgr *uefi.BootMgr) error {
info, err := mgr.ToEFIBootMgrInfo()
if err != nil {
return err
}
desc := b.desc
uefiData := jsonutils.Marshal(info)
desc.Add(uefiData, "uefi_info")
if err := b.SaveDesc(desc); err != nil {
return errors.Wrap(err, "Save uefi_info")
}
updateData := jsonutils.NewDict()
updateData.Add(uefiData, "uefi_info")
if _, err := modules.Hosts.Update(b.GetClientSession(), b.GetId(), updateData); err != nil {
return errors.Wrap(err, "Update cloud uefi info")
}
return nil
}
func (b *SBaremetalInstance) adjustServerUEFIBootOrder(srvCli *ssh.Client) error {
return b.adjustUEFIWrapper(srvCli, func() error {
info, err := b.GetUEFIInfo()
if err != nil {
return errors.Wrap(err, "GetUEFIInfo from local desc")
}
if info == nil {
return uefi.RemoteTryToSetPXEBoot(srvCli)
}
if err := uefi.RemoteTryToSetPXEBoot(srvCli); err != nil {
log.Warningf("RemoteTryToSetPXEBoot error: %v", err)
}
_, err = uefi.RemoteSetBootOrderByInfo(srvCli, info.GetPXEEntry())
return err
})
}
func (b *SBaremetalInstance) AdjustUEFIBootOrder() error {
_, err := b.sshRunWrapper(
func(hostCli *ssh.Client) ([]string, error) {
return nil, b.AdjustUEFICurrentBootOrder(hostCli)
},
func(srvCli *ssh.Client) ([]string, error) {
return nil, b.adjustServerUEFIBootOrder(srvCli)
},
)
return err
}
func (b *SBaremetalInstance) SSHReboot() error {
if !b.HasBMC() {
// try adjust uefi boot order before reboot
if err := b.AdjustUEFIBootOrder(); err != nil {
return errors.Wrap(err, "Adjust uefi boot order")
}
}
if _, err := b.sshRun("/sbin/reboot", "sudo shutdown -r now && exit"); err != nil {
if !ssh.IsExitMissingError(err) {
return errors.Wrap(err, "Try reboot")
}
}
b.ClearSSHConfig()
return nil
}
func (b *SBaremetalInstance) SSHShutdown() error {
if _, err := b.sshRun("/sbin/poweroff", "sudo shutdown -h now && exit"); err != nil {
if ssh.IsExitMissingError(err) {
return nil
}
return errors.Wrap(err, "Try poweroff")
}
return nil
}
func (b *SBaremetalInstance) GetIPMITool() *ipmitool.LanPlusIPMI {
conf := b.GetIPMIConfig()
if conf == nil {
@@ -1397,7 +1627,7 @@ func (b *SBaremetalInstance) DoPXEBoot() error {
return fmt.Errorf("Baremetal %s ipmitool is nil", b.GetId())
}
func (b *SBaremetalInstance) DoRedfishPowerOn() error {
func (b *SBaremetalInstance) doRedfishPowerOn() error {
log.Infof("Do Redfish PowerOn ........., wait")
ctx := context.Background()
b.ClearSSHConfig()
@@ -1406,7 +1636,7 @@ func (b *SBaremetalInstance) DoRedfishPowerOn() error {
err := redfishApi.Reset(ctx, "On")
if err != nil {
if httputils.ErrorCode(err) == 409 {
log.Warningf("redfishApi.Reset On fail %s", err)
return errors.Wrap(err, "redfishApi.Reset On fail, code 409")
} else {
return errors.Wrap(err, "redfishApi.Reset On")
}
@@ -1416,6 +1646,22 @@ func (b *SBaremetalInstance) DoRedfishPowerOn() error {
return fmt.Errorf("Baremetal %s redfishApi is nil", b.GetId())
}
func (b *SBaremetalInstance) DoRedfishPowerOn() error {
err := b.doRedfishPowerOn()
if err == nil {
return nil
}
var errs = []error{err}
log.Warningf("Do redfish power on error: %v, try use fallback IPMI way", err)
ipmiCli := b.GetIPMITool()
if err := ipmitool.DoReboot(ipmiCli); err != nil {
errs = append(errs, errors.Wrap(err, "Fallback to use ipmitool reboot"))
} else {
return nil
}
return errors.NewAggregate(errs)
}
/*
func (b *SBaremetalInstance) DoDiskBoot() error {
log.Infof("Do DISK Boot ........., wait")
@@ -1429,9 +1675,34 @@ func (b *SBaremetalInstance) DoDiskBoot() error {
*/
func (b *SBaremetalInstance) GetPowerStatus() (string, error) {
status, err := b.getPowerStatus()
if err != nil {
if errors.Cause(err) != types.ErrIPMIToolNull {
return "", errors.Wrap(err, "GetPowerStatus")
} else if b.HasBMC() {
return "", errors.Wrap(err, "GetPowerStatus from ipmi")
}
}
return status, nil
}
func (b *SBaremetalInstance) getPowerStatus() (string, error) {
ipmiCli := b.GetIPMITool()
if ipmiCli == nil {
return "", fmt.Errorf("Baremetal %s ipmitool is nil", b.GetId())
if cli, err := b.GetHostSSHClient(); err == nil {
cli.Close()
return types.POWER_STATUS_ON, nil
} else {
log.Warningf("Use host %s ssh client get powerstatus: %v", b.GetName(), err)
}
if cli, err := b.GetServerSSHClient(); err == nil {
cli.Close()
b.ClearSSHConfig()
return types.POWER_STATUS_ON, nil
} else {
log.Warningf("Use server %s ssh client get powerstatus: %v", b.GetServerName(), err)
}
return "", errors.Wrapf(types.ErrIPMIToolNull, "Baremetal %s", b.GetId())
}
return ipmitool.GetChassisPowerStatus(ipmiCli)
}
@@ -2111,6 +2382,15 @@ func (s *SBaremetalServer) GetDiskConfig() ([]*api.BaremetalDiskConfig, error) {
if err != nil {
return nil, err
}
if len(layouts) != 0 {
firstDisk := layouts[0]
// convert to normal order if first disk is Linux or PCIE driver
driver := firstDisk.Conf.Driver
if utils.IsInStringArray(driver, []string{baremetal.DISK_DRIVER_LINUX, baremetal.DISK_DRIVER_PCIE}) {
return baremetal.GetLayoutDiskConfig(layouts), nil
}
}
return baremetal.GetLayoutRaidConfig(layouts), nil
}
@@ -2131,7 +2411,9 @@ func (s *SBaremetalServer) DoDiskConfig(term *ssh.Client) error {
if err != nil {
return fmt.Errorf("CalculateLayout: %v", err)
}
log.Errorf("===layouts: %s", jsonutils.Marshal(layouts).PrettyString())
diskConfs := baremetal.GroupLayoutResultsByDriverAdapter(layouts)
log.Errorf("===diskConfs: %s", jsonutils.Marshal(diskConfs).PrettyString())
for _, dConf := range diskConfs {
driver := dConf.Driver
raidDrv := raiddrivers.GetDriver(driver, term)

View File

@@ -28,6 +28,30 @@ import (
"yunion.io/x/onecloud/pkg/util/dhcp"
)
const (
// ref: https://datatracker.ietf.org/doc/html/rfc4578#section-2.1
PXE_CLIENT_ARCH_INTEL_X86PC = iota
PXE_CLIENT_ARCH_NEC_PC98
PXE_CLIENT_ARCH_EFI_ITANIUM
PXE_CLIENT_ARCH_DEC_ALPHA
PXE_CLIENT_ARCH_ARC_X86
PXE_CLIENT_ARCH_INTEL_LEAN_CLIENT
PXE_CLIENT_ARCH_EFI_IA32
PXE_CLIENT_ARCH_EFI_BC
PXE_CLIENT_ARCH_EFI_XSCALE
PXE_CLIENT_ARCH_EFI_X86_64
)
func IsUEFIPxeArch(arch uint16) bool {
switch arch {
case PXE_CLIENT_ARCH_EFI_IA32:
return true
case PXE_CLIENT_ARCH_EFI_BC, PXE_CLIENT_ARCH_EFI_XSCALE, PXE_CLIENT_ARCH_EFI_X86_64:
return true
}
return false
}
func GetNicDHCPConfig(
n *types.SNic,
serverIP string,
@@ -71,9 +95,9 @@ func GetNicDHCPConfig(
if isPxe {
conf.BootServer = serverIP
switch arch {
case 7, 9:
case PXE_CLIENT_ARCH_EFI_BC, PXE_CLIENT_ARCH_EFI_X86_64:
conf.BootFile = "bootx64.efi"
case 6:
case PXE_CLIENT_ARCH_EFI_IA32:
conf.BootFile = "bootia32.efi"
default:
//if o.Options.EnableTftpHttpDownload {

View File

@@ -328,23 +328,23 @@ func (req *dhcpRequest) findBaremetalsOfAnyMac(session *mcclient.ClientSession,
// createOrUpdateBaremetal create or update baremetal by client MAC
func (req *dhcpRequest) createOrUpdateBaremetal(session *mcclient.ClientSession) (jsonutils.JSONObject, error) {
// first try UUID
ret, err := req.findBaremetalsByUuid(session)
// first try mac and is_baremetal=true
ret, err := req.findBaremetalsOfAnyMac(session, true)
if err != nil {
return nil, err
}
if len(ret.Data) == 0 {
// try mac and is_baremetal=true
ret, err = req.findBaremetalsOfAnyMac(session, true)
// try mac and host_type=baremetal
ret, err = req.findBaremetalsOfAnyMac(session, false)
if err != nil {
return nil, err
}
if len(ret.Data) == 0 {
// try mac and host_type=baremetal
ret, err = req.findBaremetalsOfAnyMac(session, false)
if err != nil {
return nil, err
}
}
if len(ret.Data) == 0 {
// try UUID
ret, err = req.findBaremetalsByUuid(session)
if err != nil {
return nil, err
}
}
switch len(ret.Data) {

View File

@@ -342,6 +342,29 @@ func (self *SBaremetalTaskBase) EnsurePowerUp() error {
return nil
}
func (self *SBaremetalTaskBase) EnsureSSHReboot() error {
if err := self.Baremetal.SSHReboot(); err != nil {
return errors.Wrap(err, "Ensure ssh reboot")
}
var (
err error
canReach bool
)
maxTries := 20
startTime := time.Now()
for count := 0; count < maxTries; count++ {
times := (count % 10) + 1
log.Infof("Try %s ssh connection after reboot %d times, %s passed", self.Baremetal.GetName(), times, time.Now().Sub(startTime))
canReach, err = self.Baremetal.SSHReachable()
if canReach {
return nil
}
time.Sleep(10 * time.Second * time.Duration(times))
}
return errors.Wrapf(err, "Test %s ssh connection after reboot", self.Baremetal.GetName())
}
func (self *SBaremetalTaskBase) NeedPXEBoot() bool {
return false
}
@@ -400,27 +423,35 @@ func (self *SBaremetalPXEBootTaskBase) InitPXEBootTask(ctx context.Context, args
self.PxeBoot = false
}
// Do soft reboot
if self.data != nil && jsonutils.QueryBoolean(self.data, "soft_boot", false) {
self.startTime = time.Now()
if err := self.Baremetal.DoPowerShutdown(true); err != nil {
// ignore error
log.Errorf("DoPowerShutdown error: %v", err)
if !self.Baremetal.HasBMC() {
// Try remote ssh reboot
if err := self.Baremetal.SSHReboot(); err != nil {
return errors.Wrap(err, "Try ssh reboot")
}
//self.CallNextStage(self, self.WaitForShutdown, nil)
self.SetStage(self.WaitForShutdown)
} else {
// Do soft reboot
if self.data != nil && jsonutils.QueryBoolean(self.data, "soft_boot", false) {
self.startTime = time.Now()
if err := self.Baremetal.DoPowerShutdown(true); err != nil {
// ignore error
log.Errorf("DoPowerShutdown error: %v", err)
}
//self.CallNextStage(self, self.WaitForShutdown, nil)
self.SetStage(self.WaitForShutdown)
return nil
return nil
}
// shutdown and power up to PXE mode
if err := self.EnsurePowerShutdown(false); err != nil {
return errors.Wrap(err, "EnsurePowerShutdown")
}
if err := self.EnsurePowerUp(); err != nil {
return errors.Wrap(err, "EnsurePowerUp to pxe")
}
}
// shutdown and power up to PXE mode
if err := self.EnsurePowerShutdown(false); err != nil {
return errors.Wrap(err, "EnsurePowerShutdown")
}
if err := self.EnsurePowerUp(); err != nil {
return errors.Wrap(err, "EnsurePowerUp to pxe")
}
// this stage will be called by baremetalInstance when pxe start notify
self.SetSSHStage(self.IPXEBootTask().OnPXEBoot)
return nil
@@ -459,3 +490,7 @@ func (self *SBaremetalPXEBootTaskBase) OnStopComplete(ctx context.Context, args
func (self *SBaremetalPXEBootTaskBase) GetName() string {
return "BaremetalPXEBootTaskBase"
}
func AdjustUEFIBootOrder(term *ssh.Client, bm IBaremetal) error {
return bm.AdjustUEFICurrentBootOrder(term)
}

View File

@@ -22,6 +22,8 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/baremetal/utils/uefi"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/ssh"
)
@@ -29,12 +31,15 @@ import (
type IServerBaseDeployTask interface {
IPXEBootTask
RemoveEFIOSEntry() bool
DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error)
PostDeploys(term *ssh.Client) error
}
type SBaremetalServerBaseDeployTask struct {
SBaremetalPXEBootTaskBase
needPXEBoot bool
}
func newBaremetalServerBaseDeployTask(
@@ -45,6 +50,7 @@ func newBaremetalServerBaseDeployTask(
) SBaremetalServerBaseDeployTask {
task := SBaremetalServerBaseDeployTask{
SBaremetalPXEBootTaskBase: newBaremetalPXEBootTaskBase(userCred, baremetal, taskId, data),
needPXEBoot: true,
}
// any inheritance must call:
// task.SetStage(task.InitPXEBootTask)
@@ -59,6 +65,10 @@ func (self *SBaremetalServerBaseDeployTask) GetName() string {
return "BaremetalServerBaseDeployTask"
}
func (self *SBaremetalServerBaseDeployTask) NeedPXEBoot() bool {
return self.needPXEBoot
}
func (self *SBaremetalServerBaseDeployTask) GetFinishAction() string {
if self.data != nil {
action, _ := self.data.GetString("on_finish")
@@ -67,6 +77,10 @@ func (self *SBaremetalServerBaseDeployTask) GetFinishAction() string {
return ""
}
func (self *SBaremetalServerBaseDeployTask) RemoveEFIOSEntry() bool {
return false
}
func (self *SBaremetalServerBaseDeployTask) DoDeploys(_ *ssh.Client) (jsonutils.JSONObject, error) {
return nil, nil
}
@@ -77,10 +91,22 @@ func (self *SBaremetalServerBaseDeployTask) PostDeploys(_ *ssh.Client) error {
func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, term *ssh.Client, args interface{}) error {
log.Infof("%s called on stage pxeboot, args: %v", self.GetName(), args)
if self.IServerBaseDeployTask().RemoveEFIOSEntry() {
if err := uefi.RemoteTryRemoveOSBootEntry(term); err != nil {
return errors.Wrap(err, "Remote uefi boot entry")
}
}
result, err := self.IServerBaseDeployTask().DoDeploys(term)
if err != nil {
return errors.Wrap(err, "Do deploy")
}
if err := AdjustUEFIBootOrder(term, self.Baremetal); err != nil {
return errors.Wrap(err, "Adjust UEFI boot order")
}
_, err = term.Run(
"/bin/sync",
"/sbin/sysctl -w vm.drop_caches=3",
@@ -88,23 +114,42 @@ func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, term
if err != nil {
return errors.Wrap(err, "Sync disk")
}
if err := self.IServerBaseDeployTask().PostDeploys(term); err != nil {
return errors.Wrap(err, "post deploy")
}
onFinishAction := self.GetFinishAction()
if utils.IsInStringArray(onFinishAction, []string{"restart", "shutdown"}) {
err = self.EnsurePowerShutdown(false)
if err != nil {
return errors.Wrap(err, "Ensure power off")
}
if onFinishAction == "restart" {
err = self.EnsurePowerUp()
if err != nil {
return errors.Wrap(err, "Ensure power up")
if self.Baremetal.HasBMC() {
if err := self.EnsurePowerShutdown(false); err != nil {
return errors.Wrap(err, "Ensure power off")
}
if onFinishAction == "restart" {
if err := self.EnsurePowerUp(); err != nil {
return errors.Wrap(err, "Ensure power up")
}
}
self.Baremetal.AutoSyncAllStatus()
} else {
if onFinishAction == "shutdown" {
log.Infof("None BMC baremetal can't shutdown when deploying")
/*
* if err := self.Baremetal.SSHShutdown(); err != nil {
* return errors.Wrap(err, "Try ssh shutdown")
* }
*/
} else {
// do restart
// hack: ssh reboot to disk
self.needPXEBoot = false
if err := self.EnsureSSHReboot(); err != nil {
return errors.Wrap(err, "Try ssh reboot")
}
}
}
self.Baremetal.SyncAllStatus(types.POWER_STATUS_ON)
}
self.Baremetal.AutoSyncAllStatus()
SetTaskComplete(self, result)
return nil
}

View File

@@ -137,22 +137,24 @@ func (task *sBaremetalPrepareTask) prepareBaremetalInfo(cli *ssh.Client) (*barem
if ipmiInfo == nil {
ipmiInfo = &types.SIPMIInfo{}
}
if !ipmiInfo.Present && ipmiEnable {
if !ipmiInfo.Verified && !ipmiInfo.Present && ipmiEnable {
ipmiInfo.Present = true
ipmiInfo.Verified = false
}
return &baremetalPrepareInfo{
sysInfo,
cpuInfo,
dmiCPUInfo,
memInfo,
nicsInfo,
diskInfo,
storageDriver,
ipmiInfo,
isolatedDevicesInfo,
}, nil
prepareInfo := &baremetalPrepareInfo{
sysInfo: sysInfo,
cpuInfo: cpuInfo,
dmiCpuInfo: dmiCPUInfo,
memInfo: memInfo,
nicsInfo: nicsInfo,
diskInfo: diskInfo,
storageDriver: storageDriver,
ipmiInfo: ipmiInfo,
isolatedDevicesInfo: isolatedDevicesInfo,
}
return prepareInfo, nil
}
func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremetalPrepareInfo) error {
@@ -313,7 +315,7 @@ func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
// set ipmi nic address and user password
if err = task.configIPMISetting(cli, infos); err != nil {
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
return err
return errors.Wrap(err, "Config IPMI setting")
}
if err = task.updateBmInfo(cli, infos); err != nil {
@@ -327,6 +329,11 @@ func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
log.Errorf("SetNTP fail: %s", err)
}
if err = AdjustUEFIBootOrder(cli, task.baremetal); err != nil {
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
return errors.Wrap(err, "Adjust UEFI boot order")
}
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, infos.sysInfo, task.userCred, true)
log.Infof("Prepare complete")
@@ -358,7 +365,7 @@ func (task *sBaremetalPrepareTask) findAdminNic(cli *ssh.Client, nicsInfo []*typ
func (task *sBaremetalPrepareTask) updateBmInfo(cli *ssh.Client, i *baremetalPrepareInfo) error {
adminNic := task.baremetal.GetAdminNic()
if adminNic == nil {
if adminNic == nil || (adminNic != nil && !adminNic.LinkUp) {
adminIdx, adminNicDev, err := task.findAdminNic(cli, i.nicsInfo)
if err != nil {
return errors.Wrap(err, "task.findAdminNic")
@@ -368,7 +375,7 @@ func (task *sBaremetalPrepareTask) updateBmInfo(cli *ssh.Client, i *baremetalPre
if err != nil {
return errors.Wrap(err, "send Admin Nic Info")
}
adminNic = task.baremetal.GetAdminNic()
adminNic = task.baremetal.GetNicByMac(adminNicDev.Mac)
}
// collect params
updateInfo := make(map[string]interface{})

View File

@@ -46,6 +46,10 @@ func (self *SBaremetalServerCreateTask) GetName() string {
return "BaremetalServerCreateTask"
}
func (self *SBaremetalServerCreateTask) RemoveEFIOSEntry() bool {
return true
}
func (self *SBaremetalServerCreateTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
// Build raid
err := self.Baremetal.GetServer().DoDiskConfig(term)
@@ -90,7 +94,10 @@ func doPoweroff(term *ssh.Client) error {
}
func (self *SBaremetalServerCreateTask) PostDeploys(term *ssh.Client) error {
return doPoweroff(term)
if self.Baremetal.HasBMC() {
return doPoweroff(term)
}
return nil
}
func (self *SBaremetalServerCreateTask) onError(term *ssh.Client, err error) error {

View File

@@ -43,6 +43,10 @@ func (self *SBaremetalServerDeployTask) GetName() string {
return "BaremetalServerDeployTask"
}
func (self *SBaremetalServerDeployTask) RemoveEFIOSEntry() bool {
return false
}
func (self *SBaremetalServerDeployTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
return self.Baremetal.GetServer().DoDeploy(term, self.data, false)
}

View File

@@ -44,6 +44,10 @@ func (self *SBaremetalServerDestroyTask) GetName() string {
return "BaremetalServerDestroyTask"
}
func (self *SBaremetalServerDestroyTask) RemoveEFIOSEntry() bool {
return true
}
func (self *SBaremetalServerDestroyTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
if err := self.Baremetal.GetServer().DoEraseDisk(term); err != nil {
log.Errorf("Delete server do erase disk: %v", err)

View File

@@ -23,6 +23,7 @@ import (
baremetaltypes "yunion.io/x/onecloud/pkg/baremetal/types"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/ssh"
)
type IBaremetal interface {
@@ -68,6 +69,12 @@ type IBaremetal interface {
SaveSSHConfig(remoteAddr string, key string) error
ServerLoadDesc() error
GetDHCPServerIP() (net.IP, error)
HasBMC() bool
SSHReachable() (bool, error)
SSHReboot() error
SSHShutdown() error
AdjustUEFICurrentBootOrder(cli *ssh.Client) error
}
type IBmManager interface {

View File

@@ -45,6 +45,10 @@ func (self *SBaremetalServerRebuildTask) GetName() string {
return "BaremetalServerRebuildTask"
}
func (self *SBaremetalServerRebuildTask) RemoveEFIOSEntry() bool {
return true
}
func (self *SBaremetalServerRebuildTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
parts, err := self.Baremetal.GetServer().DoRebuildRootDisk(term)
if err != nil {
@@ -65,5 +69,8 @@ func (self *SBaremetalServerRebuildTask) DoDeploys(term *ssh.Client) (jsonutils.
}
func (self *SBaremetalServerRebuildTask) PostDeploys(term *ssh.Client) error {
return doPoweroff(term)
if self.Baremetal.HasBMC() {
return doPoweroff(term)
}
return nil
}

View File

@@ -48,3 +48,8 @@ func (self *SBaremetalReprepareTask) DoDeploys(term *ssh.Client) (jsonutils.JSON
err := task.DoPrepare(term)
return nil, err
}
func (self *SBaremetalReprepareTask) PostDeploys(term *ssh.Client) error {
self.Baremetal.AutoSyncStatus()
return nil
}

View File

@@ -44,16 +44,22 @@ func NewBaremetalServerStartTask(
}
func (self *SBaremetalServerStartTask) DoBoot(ctx context.Context, args interface{}) error {
conf := self.Baremetal.GetRawIPMIConfig()
if !conf.CdromBoot {
err := self.Baremetal.DoPXEBoot()
if err != nil {
return errors.Wrap(err, "DoPXEBoot")
if self.Baremetal.HasBMC() {
conf := self.Baremetal.GetRawIPMIConfig()
if !conf.CdromBoot {
err := self.Baremetal.DoPXEBoot()
if err != nil {
return errors.Wrap(err, "DoPXEBoot")
}
} else {
err := self.Baremetal.DoRedfishPowerOn()
if err != nil {
return errors.Wrap(err, "DoRedfishPowerOn")
}
}
} else {
err := self.Baremetal.DoRedfishPowerOn()
if err != nil {
return errors.Wrap(err, "DoRedfishPowerOn")
if err := self.Baremetal.SSHReboot(); err != nil {
return errors.Wrap(err, "Try reboot")
}
}
self.SetStage(self.WaitForStart)
@@ -68,7 +74,7 @@ func (self *SBaremetalServerStartTask) GetName() string {
func (self *SBaremetalServerStartTask) WaitForStart(ctx context.Context, args interface{}) error {
status, err := self.Baremetal.GetPowerStatus()
if err != nil {
return errors.Wrap(err, "GetPowerStatus")
return errors.Wrap(err, "Wait for start")
}
log.Infof("%s WaitForStart status=%s", self.GetName(), status)
if status == types.POWER_STATUS_ON {

View File

@@ -46,9 +46,16 @@ func NewBaremetalServerStopTask(
}
func (task *SBaremetalServerStopTask) DoStop(ctx context.Context, args interface{}) error {
task.SetStage(task.WaitForStop)
if err := task.Baremetal.DoPowerShutdown(true); err != nil {
log.Errorf("Do power shutdown error: %s", err)
if task.Baremetal.HasBMC() {
task.SetStage(task.WaitForStop)
if err := task.Baremetal.DoPowerShutdown(true); err != nil {
log.Errorf("Do power shutdown error: %s", err)
}
} else {
if err := task.Baremetal.SSHShutdown(); err != nil {
return errors.Wrap(err, "Try ssh shutdown")
}
task.SetStage(task.OnStopComplete)
}
task.startTime = time.Now()
ExecuteTask(task, nil)

View File

@@ -16,9 +16,9 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
baremetalstatus "yunion.io/x/onecloud/pkg/baremetal/status"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
@@ -45,14 +45,23 @@ func NewBaremetalUnmaintenanceTask(
func (task *SBaremetalUnmaintenanceTask) DoUnmaintenance(ctx context.Context, args interface{}) error {
var err error
if jsonutils.QueryBoolean(task.data, "guest_running", false) {
err = task.EnsurePowerShutdown(false)
if err != nil {
return fmt.Errorf("EnsurePowerShutdown hard: %v", err)
}
err = task.EnsurePowerUp()
if err != nil {
return fmt.Errorf("EnsurePowerUp disk: %v", err)
hasBMC := task.Baremetal.HasBMC()
if jsonutils.QueryBoolean(task.data, "guest_running", false) || !hasBMC {
if hasBMC {
err = task.EnsurePowerShutdown(false)
if err != nil {
return errors.Errorf("EnsurePowerShutdown hard: %v", err)
}
err = task.EnsurePowerUp()
if err != nil {
return errors.Errorf("EnsurePowerUp disk: %v", err)
}
} else {
if task.Baremetal.GetServer() != nil {
if err := task.EnsureSSHReboot(); err != nil {
return errors.Wrap(err, "Do unmaintenance for none BMC server")
}
}
}
task.Baremetal.SyncStatus(baremetalstatus.RUNNING, "")
SetTaskComplete(task, nil)
@@ -61,7 +70,7 @@ func (task *SBaremetalUnmaintenanceTask) DoUnmaintenance(ctx context.Context, ar
task.SetStage(task.WaitForStop)
err = task.EnsurePowerShutdown(true)
if err != nil {
return fmt.Errorf("EnsurePowerShutdown soft: %v", err)
return errors.Errorf("EnsurePowerShutdown soft: %v", err)
}
ExecuteTask(task, nil)
return nil

View File

@@ -36,6 +36,7 @@ type IBaremetalServer interface {
SyncPartitionSize(term *ssh.Client, parts []*disktool.Partition) ([]jsonutils.JSONObject, error)
DoDeploy(term *ssh.Client, data jsonutils.JSONObject, isInit bool) (jsonutils.JSONObject, error)
SaveDesc(desc jsonutils.JSONObject) error
GetNics() []types.SServerNic
GetNicByMac(mac net.HardwareAddr) *types.SNic
GetRootTemplateId() string

View File

@@ -616,7 +616,24 @@ func (tool *PartitionTool) parseLsDisk(lines []string, driver string) {
}
minCnt := int(math.Min(float64(len(disks)), float64(len(tool.diskTable[driver]))))
for i := 0; i < minCnt; i++ {
tool.diskTable[driver][i].SetInfo(disks[i])
driverDisk := tool.diskTable[driver][i]
if utils.IsInStringArray(driver, []string{NONRAID_DRIVER, PCIE_DRIVER}) {
// find size matched disk from disks
size := driverDisk.sizeMB
var remoteDisk *types.SDiskInfo
for ri := range disks {
if disks[ri].Size == size {
remoteDisk = disks[ri]
// remove matched disks
disks = append(disks[:ri], disks[ri+1:]...)
break
}
}
driverDisk.SetInfo(remoteDisk)
} else {
// raid disk set by order
driverDisk.SetInfo(disks[i])
}
}
}

View File

@@ -20,9 +20,8 @@ import (
"strconv"
"strings"
"github.com/pkg/errors"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/stringutils"
"yunion.io/x/pkg/utils"
@@ -382,11 +381,18 @@ func (r *HPSARaid) parsePhyDevs(lines []string) error {
r.adapters = append(r.adapters, adapter)
}
}
var errs []error
for _, a := range r.adapters {
if err := a.ParsePhyDevs(); err != nil {
return err
err := a.ParsePhyDevs()
if err != nil {
log.Errorf("parse adapter %d fail: %s", a.GetIndex(), err)
errs = append(errs, err)
}
}
if len(errs) == len(r.adapters) {
// all failed
return errors.NewAggregate(errs)
}
return nil
}

View File

@@ -615,6 +615,7 @@ func (adapter *MegaRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage
type StorcliAdaptor struct {
Controller int
isSNEmpty bool
sn string
name string
}
@@ -622,6 +623,7 @@ type StorcliAdaptor struct {
func newStorcliAdaptor() *StorcliAdaptor {
return &StorcliAdaptor{
Controller: -1,
isSNEmpty: false,
sn: "",
name: "",
}
@@ -632,26 +634,56 @@ func (a StorcliAdaptor) key() string {
}
func (a *StorcliAdaptor) isComplete() bool {
if a.isSNEmpty {
return a.Controller >= 0 && a.name != ""
}
return a.Controller >= 0 && a.name != "" && a.sn != ""
}
func (a *StorcliAdaptor) parseLine(l string) {
parts := strings.Split(l, " = ")
func parseLineForStorcli(a *StorcliAdaptor, l string) {
controllerKey := "Controller"
productNameKey := "Product Name"
snKey := "Serial Number"
if !regexp.MustCompile(fmt.Sprintf("^(%s|%s|%s)\\s*=", controllerKey, productNameKey, snKey)).Match([]byte(l)) {
return
}
parts := strings.Split(l, "=")
if len(parts) != 2 {
return
}
key := parts[0]
val := parts[1]
trimBeginEndSpace := func(s string) string {
return strings.TrimLeft(strings.TrimRight(s, " "), " ")
}
key := trimBeginEndSpace(parts[0])
val := trimBeginEndSpace(parts[1])
if key == snKey && val == "" {
a.isSNEmpty = true
return
}
switch key {
case "Controller":
case controllerKey:
a.Controller, _ = strconv.Atoi(val)
case "Serial Number":
case snKey:
a.sn = val
case "Product Name":
case productNameKey:
a.name = val
}
}
func (a *StorcliAdaptor) parseLine(l string) {
parseLineForStorcli(a, l)
}
func (a *StorcliAdaptor) String() string {
return fmt.Sprintf("{controller: %d, isSNEmpty: %v, sn: %q, name: %s}", a.Controller, a.isSNEmpty, a.sn, a.name)
}
func (raid *MegaRaid) GetStorcliAdaptor() (map[string]*StorcliAdaptor, error) {
ret := make(map[string]*StorcliAdaptor)
cmd := GetCommand2("/call", "show", "|", "grep", "-iE", `'^(Controller|Product Name|Serial Number)\s='`)

View File

@@ -0,0 +1,118 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package megactl
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseLineForStorcli(t *testing.T) {
type testCase struct {
name string
adapter *StorcliAdaptor
lines []string
assertFunc func(t *testing.T, a *StorcliAdaptor)
}
cases := []testCase{
{
name: "Should complete",
adapter: new(StorcliAdaptor),
lines: []string{
"Controller = 0",
"Product Name = SAS3108",
"Serial Number = 1234",
},
assertFunc: func(t *testing.T, a *StorcliAdaptor) {
assert.Equal(t, true, a.isComplete(), a.String())
assert.Equal(t, "SAS3108"+"1234", a.key())
},
},
{
name: "Should complete when no space beside '='",
adapter: new(StorcliAdaptor),
lines: []string{
"Controller=0",
"Product Name = SAS3108",
"Serial Number=1234",
},
assertFunc: func(t *testing.T, a *StorcliAdaptor) {
assert.Equal(t, true, a.isComplete(), a.String())
assert.Equal(t, "SAS3108"+"1234", a.key())
},
},
{
name: "Should parse empty SN",
adapter: new(StorcliAdaptor),
lines: []string{
"Controller = 0",
"Product Name = SAS3108",
"Serial Number =",
},
assertFunc: func(t *testing.T, a *StorcliAdaptor) {
assert.Equal(t, true, a.isComplete(), a.String())
assert.Equal(t, true, a.isSNEmpty, a.String())
assert.Equal(t, "SAS3108", a.key())
},
},
{
name: "Should parse empty SN end with space",
adapter: new(StorcliAdaptor),
lines: []string{
"Controller = 0",
"Product Name = SAS3108",
"Serial Number = ",
},
assertFunc: func(t *testing.T, a *StorcliAdaptor) {
assert.Equal(t, true, a.isComplete(), a.String())
assert.Equal(t, true, a.isSNEmpty, a.String())
assert.Equal(t, "SAS3108", a.key())
},
},
{
name: "Should not complete when no product name",
adapter: new(StorcliAdaptor),
lines: []string{
"Controller = 0",
"Serial Number = 1234",
},
assertFunc: func(t *testing.T, a *StorcliAdaptor) {
assert.Equal(t, false, a.isComplete(), a.String())
},
},
{
name: "Should not complete when no SN",
adapter: new(StorcliAdaptor),
lines: []string{
"Controller = 0",
"Product Name = SAS3108",
},
assertFunc: func(t *testing.T, a *StorcliAdaptor) {
assert.Equal(t, false, a.isComplete(), a.String())
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
for _, l := range c.lines {
parseLineForStorcli(c.adapter, l)
}
c.assertFunc(t, c.adapter)
})
}
}

View File

@@ -0,0 +1 @@
package uefi // import "yunion.io/x/onecloud/pkg/baremetal/utils/uefi"

View File

@@ -0,0 +1,478 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package uefi
import (
"fmt"
"strconv"
"strings"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/util/regutils2"
"yunion.io/x/onecloud/pkg/util/ssh"
)
const (
// efibootmgr useage: https://github.com/rhboot/efibootmgr
CMD_EFIBOOTMGR = "/usr/sbin/efibootmgr"
SUDO_EFIBOOTMGR = "sudo efibootmgr"
MAC_KEYWORD = "MAC"
)
type BootMgr struct {
// bootCurrent - the boot entry used to start the currently running system.
bootCurrent string
// bootOrder - the boot order as would appear in the boot manager.
// The boot manager tries to boot the first active entry on this list.
// If unsuccessful, it tries the next entry, and so on.
bootOrder []string
// bootNext - the boot entry which is scheduled to be run on next boot.
// This superceeds BootOrder for one boot only, and is deleted by the
// boot manager after first use.
// This allows you to change the next boot behavior without changing BootOrder.
bootNext string
// timeout - the time in seconds between when the boot manager appears on the screen
// until when it automatically chooses the startup value from BootNext or BootOrder.
timeout int
// entries - the boot entry parsed in map
entries map[string]*BootEntry
}
type BootEntry struct {
BootNum string
Description string
IsActive bool
}
func getEFIBootMgrCmd(sudo bool) string {
if sudo {
return SUDO_EFIBOOTMGR
}
return CMD_EFIBOOTMGR
}
func ParseEFIBootMGR(input string) (*BootMgr, error) {
lines := strings.Split(input, "\n")
mgr := &BootMgr{
bootOrder: []string{},
timeout: -1,
entries: make(map[string]*BootEntry),
}
pf := func(ff func(string) bool) {
for _, l := range lines {
if ok := ff(l); ok {
break
}
}
}
// parse BootCurrent
pf(func(l string) bool {
if current := parseEFIBootMGRBootCurrent(l); current != "" {
mgr.bootCurrent = current
return true
}
return false
})
// parse Timeout second
pf(func(l string) bool {
if timeout := parseEFIBootMGRTimeout(l); timeout != -1 {
mgr.timeout = timeout
return true
}
return false
})
// parse BootOrder
pf(func(l string) bool {
if order := parseEFIBootMGRBootOrder(l); len(order) != 0 {
mgr.bootOrder = order
return true
}
return false
})
// parse BootNext
pf(func(l string) bool {
if next := parseEFIBootMGRBootNext(l); next != "" {
mgr.bootNext = next
return true
}
return false
})
// parse entries
pf(func(l string) bool {
if entry := parseEFIBootMGREntry(l); entry != nil {
mgr.entries[entry.BootNum] = entry
}
return false
})
// finally check
if err := mgr.DataCheck(); err != nil {
return nil, errors.Wrap(err, "Invalid efibootmgr parse")
}
return mgr, nil
}
func (m *BootMgr) DataCheck() error {
if m.bootCurrent == "" {
return errors.Error("BootCurrent is empty")
}
if len(m.bootOrder) == 0 {
return errors.Error("BootOrder length is 0")
}
// check if BootOrder in entries
for _, orderNum := range m.bootOrder {
if _, ok := m.entries[orderNum]; !ok {
return errors.Errorf("Not found BootOrder %s entry", orderNum)
}
}
return nil
}
func parseEFIBootMGRBootCurrent(line string) string {
prefix := "BootCurrent: "
if strings.HasPrefix(line, prefix) {
return strings.Split(line, prefix)[1]
}
return ""
}
func parseEFIBootMGRBootOrder(line string) []string {
prefix := "BootOrder: "
if !strings.HasPrefix(line, prefix) {
return nil
}
orderStr := strings.Split(line, prefix)[1]
return strings.Split(orderStr, ",")
}
func parseEFIBootMGRBootNext(line string) string {
prefix := "BootNext: "
if !strings.HasPrefix(line, prefix) {
return ""
}
return strings.Split(line, prefix)[1]
}
func parseEFIBootMGRTimeout(line string) int {
timeoutRegexp := `^Timeout: (?P<seconds>[0-9]{1,}) seconds`
matches := regutils2.SubGroupMatch(timeoutRegexp, line)
if len(matches) == 0 {
return -1
}
secondStr := matches["seconds"]
second, err := strconv.Atoi(secondStr)
if err != nil {
log.Errorf("parse %s seconds error: %v", secondStr, err)
return -1
}
return second
}
func parseEFIBootMGREntry(line string) *BootEntry {
entryRegexp := `^Boot(?P<num>[0-9a-zA-Z]{4})[^:]+?\s+(?P<description>.*)`
matches := regutils2.SubGroupMatch(entryRegexp, line)
if len(matches) == 0 {
return nil
}
num, ok := matches["num"]
if !ok {
return nil
}
desc, ok := matches["description"]
if !ok {
return nil
}
isActive := false
if strings.Contains(line, "* ") {
isActive = true
}
return &BootEntry{
BootNum: num,
Description: desc,
IsActive: isActive,
}
}
func NewEFIBootMgrFromRemote(cli *ssh.Client, sudo bool) (*BootMgr, error) {
return newEFIBootMgrFromRemote(cli, sudo, true)
}
func newEFIBootMgrFromRemote(cli *ssh.Client, sudo bool, verbose bool) (*BootMgr, error) {
cmd := getEFIBootMgrCmd(sudo)
if verbose {
cmd = fmt.Sprintf("%s -v", cmd)
}
lines, err := cli.RawRun(cmd)
if err != nil {
return nil, errors.Wrapf(err, "Execute command: %s", cmd)
}
return ParseEFIBootMGR(strings.Join(lines, "\n"))
}
func (m *BootMgr) GetCommand(sudo bool) string {
return getEFIBootMgrCmd(sudo)
}
func (m *BootMgr) GetBootCurrent() string {
return m.bootCurrent
}
func (m *BootMgr) GetBootOrder() []string {
return m.bootOrder
}
func (m *BootMgr) GetBootNext() string {
return m.bootNext
}
func (m *BootMgr) GetTimeout() int {
return m.timeout
}
func (m *BootMgr) GetBootEntry(num string) *BootEntry {
return m.entries[num]
}
func (m *BootMgr) GetBootEntryByDesc(desc string) *BootEntry {
for _, entry := range m.entries {
if strings.Contains(entry.Description, desc) {
return entry
}
}
return nil
}
func (m *BootMgr) FindBootOrderPos(num string) int {
return stringArraryFindItemPos(m.bootOrder, num)
}
func stringArraryFindItemPos(items []string, item string) int {
for idx, elem := range items {
if elem == item {
return idx
}
}
return -1
}
func stringArraryMove(items []string, item string, pos int) []string {
origPos := stringArraryFindItemPos(items, item)
if origPos == -1 {
items = append(items, item)
origPos = stringArraryFindItemPos(items, item)
}
for i := origPos; i != pos; {
if i < pos {
// from left to right
tmp := items[i]
items[i] = items[i+1]
items[i+1] = tmp
i++
} else if i > pos {
// from right to left
tmp := items[i]
items[i] = items[i-1]
items[i-1] = tmp
i--
}
}
return items
}
func (m *BootMgr) MoveBootOrder(num string, pos int) *BootMgr {
if entry := m.GetBootEntry(num); entry == nil {
log.Warningf("Not found boot entry by %q", num)
return m
}
m.bootOrder = stringArraryMove(m.bootOrder, num, pos)
return m
}
func getSetBootOrderArgs(bootOrder []string) string {
return strings.Join(bootOrder, ",")
}
func (m *BootMgr) GetSetBootOrderArgs() string {
return getSetBootOrderArgs(m.bootOrder)
}
func RemoteIsUEFIBoot(cli *ssh.Client) (bool, error) {
checkCmd := "test -d /sys/firmware/efi && echo is || echo not"
lines, err := cli.Run(checkCmd)
if err != nil {
return false, err
}
for _, line := range lines {
if strings.Contains(line, "is") {
return true, nil
}
}
return false, nil
}
func convertToEFIBootMgrInfo(info *BootMgr) (*types.EFIBootMgrInfo, error) {
data := &types.EFIBootMgrInfo{
PxeBootNum: info.GetBootCurrent(),
BootOrder: make([]*types.EFIBootEntry, len(info.GetBootOrder())),
}
for idx, orderNum := range info.GetBootOrder() {
entry := info.GetBootEntry(orderNum)
if entry == nil {
return nil, errors.Errorf("Not found boot entry by %q", orderNum)
}
data.BootOrder[idx] = &types.EFIBootEntry{
BootNum: entry.BootNum,
Description: entry.Description,
IsActive: entry.IsActive,
}
}
return data, nil
}
func (mgr *BootMgr) ToEFIBootMgrInfo() (*types.EFIBootMgrInfo, error) {
return convertToEFIBootMgrInfo(mgr)
}
func (mgr *BootMgr) sortEntryByKeyword(keyword string) *BootMgr {
newOrder := []string{}
oldOrder := []string{}
for _, num := range mgr.bootOrder {
entry := mgr.GetBootEntry(num)
if strings.Contains(entry.Description, keyword) {
newOrder = append(newOrder, num)
} else {
oldOrder = append(oldOrder, num)
}
}
newOrder = append(newOrder, oldOrder...)
mgr.bootOrder = newOrder
return mgr
}
func RemoteSetCurrentBootAtFirst(cli *ssh.Client, mgr *BootMgr) error {
curPos := mgr.FindBootOrderPos(mgr.GetBootCurrent())
if curPos == -1 {
return errors.Errorf("Not found BootCurrent position %q", mgr.GetBootCurrent())
}
// move to first
mgr.MoveBootOrder(mgr.GetBootCurrent(), 0)
cmd := fmt.Sprintf("%s -o %s", mgr.GetCommand(false), mgr.GetSetBootOrderArgs())
_, err := cli.Run(cmd)
return err
}
func RemoteSetBootOrder(cli *ssh.Client, order []string) error {
cmd := fmt.Sprintf("%s -o %s", SUDO_EFIBOOTMGR, getSetBootOrderArgs(order))
_, err := cli.RunWithTTY(cmd)
return err
}
func RemoteSetBootOrderByInfo(cli *ssh.Client, entry *types.EFIBootEntry) (*BootMgr, error) {
mgr, err := newEFIBootMgrFromRemote(cli, true, true)
if err != nil {
return nil, err
}
curEntry := mgr.GetBootEntryByDesc(entry.Description)
if curEntry == nil {
return nil, errors.Wrapf(err, "Not found remote boot entry by %q", entry.Description)
}
mgr = mgr.sortEntryByKeyword(curEntry.Description)
return mgr, RemoteSetBootOrder(cli, mgr.GetBootOrder())
}
func RemoteTryToSetPXEBoot(cli *ssh.Client) error {
mgr, err := newEFIBootMgrFromRemote(cli, true, true)
if err != nil {
return err
}
mgr = mgr.sortEntryByKeyword(MAC_KEYWORD)
return RemoteSetBootOrder(cli, mgr.GetBootOrder())
}
func remoteISUEFIBootWrap(cli *ssh.Client, f func(*ssh.Client) error) error {
isUEFI, err := RemoteIsUEFIBoot(cli)
if err != nil {
return errors.Wrap(err, "Check is UEFI boot")
}
if !isUEFI {
return nil
}
return f(cli)
}
func RemoteTryRemoveOSBootEntry(hostCli *ssh.Client) error {
return remoteISUEFIBootWrap(hostCli, remoteTryRemoveOSBootEntry)
}
func remoteTryRemoveOSBootEntry(hostCli *ssh.Client) error {
mgr, err := newEFIBootMgrFromRemote(hostCli, false, true)
if err != nil {
return err
}
// TODO: find other ways to decide whether entry is OS boot
osKeywords := []string{
"linux",
"centos",
"ubuntu",
"windows",
"grub",
}
isOsEntry := func(desc string) bool {
for _, key := range osKeywords {
desc := strings.ToLower(desc)
if strings.Contains(desc, key) {
return true
}
}
return false
}
for _, entry := range mgr.entries {
if !isOsEntry(entry.Description) {
continue
}
// delete entry and remove it from BootOrder
cmd := fmt.Sprintf("%s -b %s -B", mgr.GetCommand(false), entry.BootNum)
if _, err := hostCli.Run(cmd); err != nil {
return errors.Wrapf(err, "remove boot entry: %s", entry.Description)
}
}
return nil
}

View File

@@ -0,0 +1,316 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package uefi
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
const (
TestPCOutput = `BootCurrent: 0007
Timeout: 2 seconds
BootOrder: 0003,0002,0001,0000,0004,0005,0007,0008,0009,000A
Boot0000 Windows Boot Manager
Boot0001 ubuntu
Boot0002 ubuntu
Boot0003 CentOS Linux
Boot0004* Onboard NIC(IPV4)
Boot0005 Onboard NIC(IPV6)
Boot0007* PXE IPv4 Intel(R) Ethernet Server Adapter X520-2
Boot0008 PXE IPv6 Intel(R) Ethernet Server Adapter X520-2
Boot0009* PXE IPv4 Intel(R) Ethernet Server Adapter X520-2
Boot000A PXE IPv6 Intel(R) Ethernet Server Adapter X520-2`
TestQemuOutput = `BootCurrent: 0005
Timeout: 0 seconds
BootOrder: 0005,0009,0008,0007,0002,0003,0004,0006,0001,0000
Boot0000* UiApp
Boot0001* UEFI QEMU DVD-ROM QM00003
Boot0002* UEFI Floppy
Boot0003* UEFI Floppy 2
Boot0004* UEFI QEMU HARDDISK QM00001
Boot0005* UEFI PXEv4 (MAC:525400123456)
Boot0006* EFI Internal Shell
Boot0007* CentOS
Boot0008* CentOS Linux
Boot0009* ubuntu`
)
func Test_parseTimeout(t *testing.T) {
tests := []struct {
input string
want int
}{
{
input: "Timeout: 0 seconds",
want: 0,
},
{
input: "Timeout: 30 seconds",
want: 30,
},
{
input: "Timeout: seconds",
want: -1,
},
}
for _, tc := range tests {
if got := parseEFIBootMGRTimeout(tc.input); !reflect.DeepEqual(got, tc.want) {
t.Errorf("parseEFIBootMGRTimeout() = %v, want %v", got, tc.want)
}
}
}
func Test_parseEFIBootMGRBootOrder(t *testing.T) {
tests := []struct {
input string
want []string
}{
{
input: "BootOrder: 0005,0009,0008,0007,0002,0003,0004,0006,0001,0000",
want: []string{"0005", "0009", "0008", "0007", "0002", "0003", "0004", "0006", "0001", "0000"},
},
}
for _, tc := range tests {
if got := parseEFIBootMGRBootOrder(tc.input); !reflect.DeepEqual(got, tc.want) {
t.Errorf("parseEFIBootMGRBootOrder() = %v, want %v", got, tc.want)
}
}
}
func Test_parseEFIBootMGRBootCurrent(t *testing.T) {
tests := []struct {
name string
line string
want string
}{
{
name: "BootCurrent: 0005",
line: "BootCurrent: 0005",
want: "0005",
},
{
name: "BootCurrent: ",
line: "BootCurrent: ",
want: "",
},
{
name: "BootCurrent:",
line: "BootCurrent:",
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := parseEFIBootMGRBootCurrent(tt.line); got != tt.want {
t.Errorf("parseEFIBootMGRBootCurrent() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseEFIBootMGREntry(t *testing.T) {
tests := []struct {
name string
line string
want *BootEntry
}{
{
name: "Boot0009* ubuntu",
line: "Boot0009* ubuntu",
want: &BootEntry{
BootNum: "0009",
Description: "ubuntu",
IsActive: true,
},
},
{
name: "Boot0005* UEFI PXEv4 (MAC:525400123456)",
line: "Boot0005* UEFI PXEv4 (MAC:525400123456)",
want: &BootEntry{
BootNum: "0005",
Description: "UEFI PXEv4 (MAC:525400123456)",
IsActive: true,
},
},
{
name: "Boot0003 CentOS Linux",
line: "Boot0003 CentOS Linux",
want: &BootEntry{
BootNum: "0003",
Description: "CentOS Linux",
IsActive: false,
},
},
{
name: "Timeout: 2 seconds",
line: "Timeout: 2 seconds",
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := parseEFIBootMGREntry(tt.line); !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseEFIBootMGREntry() = %v, want %v", got, tt.want)
}
})
}
}
func TestParseEFIBootMGR(t *testing.T) {
tests := []struct {
name string
input string
want *BootMgr
wantErr bool
}{
{
name: "Parse PC output",
input: TestPCOutput,
want: &BootMgr{
bootCurrent: "0007",
timeout: 2,
bootOrder: []string{"0003", "0002", "0001", "0000", "0004", "0005", "0007", "0008", "0009", "000A"},
entries: map[string]*BootEntry{
"0000": {
BootNum: "0000",
IsActive: false,
Description: "Windows Boot Manager",
},
"0001": {
BootNum: "0001",
IsActive: false,
Description: "ubuntu",
},
"0002": {
BootNum: "0002",
IsActive: false,
Description: "ubuntu",
},
"0003": {
BootNum: "0003",
IsActive: false,
Description: "CentOS Linux",
},
"0004": {
BootNum: "0004",
IsActive: true,
Description: "Onboard NIC(IPV4)",
},
"0005": {
BootNum: "0005",
IsActive: false,
Description: "Onboard NIC(IPV6)",
},
"0007": {
BootNum: "0007",
IsActive: true,
Description: "PXE IPv4 Intel(R) Ethernet Server Adapter X520-2",
},
"0008": {
BootNum: "0008",
IsActive: false,
Description: "PXE IPv6 Intel(R) Ethernet Server Adapter X520-2",
},
"0009": {
BootNum: "0009",
IsActive: true,
Description: "PXE IPv4 Intel(R) Ethernet Server Adapter X520-2",
},
"000A": {
BootNum: "000A",
IsActive: false,
Description: "PXE IPv6 Intel(R) Ethernet Server Adapter X520-2",
},
}},
},
}
assert := assert.New(t)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseEFIBootMGR(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("ParseEFIBootMGR() error = %v, wantErr %v", err, tt.wantErr)
return
}
if equal := assert.Equal(tt.want, got); !equal {
t.Errorf("ParseEFIBootMGR() = %v, want %v", got, tt.want)
}
})
}
}
func Test_stringArraryMove(t *testing.T) {
type args struct {
items []string
item string
pos int
}
tests := []struct {
name string
args args
want []string
}{
{
name: "move left to right",
args: args{
items: []string{"1", "2", "3"},
item: "3",
pos: 0,
},
want: []string{"3", "1", "2"},
},
{
name: "move right to left",
args: args{
items: []string{"1", "2", "3"},
item: "1",
pos: 2,
},
want: []string{"2", "3", "1"},
},
{
name: "no move",
args: args{
items: []string{"1", "2", "3"},
item: "2",
pos: 1,
},
want: []string{"1", "2", "3"},
},
{
name: "add item move",
args: args{
items: []string{"1", "2", "3"},
item: "4",
pos: 0,
},
want: []string{"4", "1", "2", "3"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := stringArraryMove(tt.args.items, tt.args.item, tt.args.pos); !reflect.DeepEqual(got, tt.want) {
t.Errorf("stringArraryMove() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -91,7 +91,7 @@ func ValidateCreateDomainId(domainId string) error {
func (manager *SDomainizedResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
switch field {
case "domain":
tenantCacheQuery := TenantCacheManager.GetDomainQuery("name", "id").SubQuery()
tenantCacheQuery := TenantCacheManager.getTable() // GetDomainQuery("name", "id").SubQuery()
q = q.AppendField(tenantCacheQuery.Field("name", "domain")).Distinct()
q = q.Join(tenantCacheQuery, sqlchemy.Equals(q.Field("domain_id"), tenantCacheQuery.Field("id")))
return q, nil

View File

@@ -24,6 +24,7 @@ import (
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -69,6 +70,51 @@ func (self *SEnabledStatusInfrasResourceBase) PerformDisable(ctx context.Context
return nil, nil
}
func (manager *SEnabledStatusInfrasResourceBaseManager) AllowGetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return IsAdminAllowGetSpec(userCred, manager, "statistics")
}
func (manager *SEnabledStatusInfrasResourceBaseManager) GetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (map[string]apis.StatusStatistic, error) {
im, ok := manager.GetVirtualObject().(IModelManager)
if !ok {
im = manager
}
var err error
q := manager.Query()
q, err = ListItemFilter(im, ctx, q, userCred, query)
if err != nil {
return nil, err
}
sq := q.SubQuery()
statQ := sq.Query(sq.Field("status"), sqlchemy.COUNT("total_count", sq.Field("id")))
_, queryScope, err := FetchCheckQueryOwnerScope(ctx, userCred, query, im, rbacutils.ActionList, true)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
statQ = manager.FilterByOwner(statQ, userCred, queryScope)
statQ = manager.FilterBySystemAttributes(statQ, userCred, query, queryScope)
statQ = manager.FilterByHiddenSystemAttributes(statQ, userCred, query, queryScope)
statQ = statQ.GroupBy(sq.Field("status"))
ret := []struct {
Status string
TotalCount int64
}{}
err = statQ.All(&ret)
if err != nil {
return nil, errors.Wrapf(err, "q.All")
}
result := map[string]apis.StatusStatistic{}
for _, s := range ret {
result[s.Status] = apis.StatusStatistic{
TotalCount: s.TotalCount,
}
}
return result, nil
}
func (manager *SEnabledStatusInfrasResourceBaseManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,

View File

@@ -282,6 +282,9 @@ const (
ACT_UPDATE_RULE = "update_config"
ACT_UPDATE_TAGS = "update_tags"
ACT_UPDATE_MONITOR_RESOURCE_JOINT = "update_monitor_resource_joint"
ACT_DETACH_MONITOR_RESOURCE_JOINT = "detach_monitor_resource_joint"
ACT_MERGE_NETWORK = "merge_network"
ACT_MERGE_NETWORK_FAILED = "merge_network_failed"
)

View File

@@ -77,7 +77,7 @@ func (manager *SProjectizedResourceBaseManager) FetchOwnerId(ctx context.Context
func (manager *SProjectizedResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
switch field {
case "tenant":
tenantCacheQuery := TenantCacheManager.GetTenantQuery("name", "id").Distinct().SubQuery()
tenantCacheQuery := TenantCacheManager.getTable() // GetTenantQuery("name", "id").Distinct().SubQuery()
q.AppendField(tenantCacheQuery.Field("name", "tenant")).Distinct()
q = q.Join(tenantCacheQuery, sqlchemy.Equals(q.Field("tenant_id"), tenantCacheQuery.Field("id")))
return q, nil

View File

@@ -24,6 +24,7 @@ import (
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -55,6 +56,51 @@ func (self *SStatusInfrasResourceBase) GetIStatusInfrasModel() IStatusInfrasMode
return self.GetVirtualObject().(IStatusInfrasModel)
}
func (manager *SStatusInfrasResourceBaseManager) AllowGetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return IsAdminAllowGetSpec(userCred, manager, "statistics")
}
func (manager *SStatusInfrasResourceBaseManager) GetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (map[string]apis.StatusStatistic, error) {
im, ok := manager.GetVirtualObject().(IModelManager)
if !ok {
im = manager
}
var err error
q := manager.Query()
q, err = ListItemFilter(im, ctx, q, userCred, query)
if err != nil {
return nil, err
}
sq := q.SubQuery()
statQ := sq.Query(sq.Field("status"), sqlchemy.COUNT("total_count", sq.Field("id")))
_, queryScope, err := FetchCheckQueryOwnerScope(ctx, userCred, query, im, rbacutils.ActionList, true)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
statQ = manager.FilterByOwner(statQ, userCred, queryScope)
statQ = manager.FilterBySystemAttributes(statQ, userCred, query, queryScope)
statQ = manager.FilterByHiddenSystemAttributes(statQ, userCred, query, queryScope)
statQ = statQ.GroupBy(sq.Field("status"))
ret := []struct {
Status string
TotalCount int64
}{}
err = statQ.All(&ret)
if err != nil {
return nil, errors.Wrapf(err, "q.All")
}
result := map[string]apis.StatusStatistic{}
for _, s := range ret {
result[s.Status] = apis.StatusStatistic{
TotalCount: s.TotalCount,
}
}
return result, nil
}
// 更新资源状态
func (self *SStatusInfrasResourceBase) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
err := StatusBasePerformStatus(self.GetIStatusInfrasModel(), userCred, input)

View File

@@ -24,6 +24,7 @@ import (
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -55,6 +56,51 @@ func (self *SStatusStandaloneResourceBase) GetIStatusStandaloneModel() IStatusSt
return self.GetVirtualObject().(IStatusStandaloneModel)
}
func (manager *SStatusStandaloneResourceBaseManager) AllowGetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return IsAdminAllowGetSpec(userCred, manager, "statistics")
}
func (manager *SStatusStandaloneResourceBaseManager) GetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (map[string]apis.StatusStatistic, error) {
im, ok := manager.GetVirtualObject().(IModelManager)
if !ok {
im = manager
}
var err error
q := manager.Query()
q, err = ListItemFilter(im, ctx, q, userCred, query)
if err != nil {
return nil, err
}
sq := q.SubQuery()
statQ := sq.Query(sq.Field("status"), sqlchemy.COUNT("total_count", sq.Field("id")))
_, queryScope, err := FetchCheckQueryOwnerScope(ctx, userCred, query, im, rbacutils.ActionList, true)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
statQ = manager.FilterByOwner(statQ, userCred, queryScope)
statQ = manager.FilterBySystemAttributes(statQ, userCred, query, queryScope)
statQ = manager.FilterByHiddenSystemAttributes(statQ, userCred, query, queryScope)
statQ = statQ.GroupBy(sq.Field("status"))
ret := []struct {
Status string
TotalCount int64
}{}
err = statQ.All(&ret)
if err != nil {
return nil, errors.Wrapf(err, "q.All")
}
result := map[string]apis.StatusStatistic{}
for _, s := range ret {
result[s.Status] = apis.StatusStatistic{
TotalCount: s.TotalCount,
}
}
return result, nil
}
// 更新资源状态
func (self *SStatusStandaloneResourceBase) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
err := StatusBasePerformStatus(self.GetIStatusStandaloneModel(), userCred, input)

View File

@@ -87,6 +87,57 @@ func (manager *SVirtualResourceBaseManager) GetIVirtualModelManager() IVirtualMo
return q
}*/
func (manager *SVirtualResourceBaseManager) AllowGetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return IsAdminAllowGetSpec(userCred, manager, "statistics")
}
func (manager *SVirtualResourceBaseManager) GetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (map[string]apis.StatusStatistic, error) {
im, ok := manager.GetVirtualObject().(IModelManager)
if !ok {
im = manager
}
var err error
q := manager.Query()
q, err = ListItemFilter(im, ctx, q, userCred, query)
if err != nil {
return nil, err
}
sq := q.SubQuery()
statQ := sq.Query(sq.Field("status"), sqlchemy.COUNT("total_count", sq.Field("id")), sqlchemy.SUM("pending_deleted_count", sq.Field("pending_deleted")))
_, queryScope, err := FetchCheckQueryOwnerScope(ctx, userCred, query, manager, rbacutils.ActionList, true)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
statQ = manager.FilterByOwner(statQ, userCred, queryScope)
statQ = manager.FilterBySystemAttributes(statQ, userCred, query, queryScope)
statQ = manager.FilterByHiddenSystemAttributes(statQ, userCred, query, queryScope)
statQ = statQ.GroupBy(sq.Field("status"))
ret := []struct {
Status string
TotalCount int64
PendingDeletedCount int64
}{}
err = statQ.All(&ret)
if err != nil {
return nil, errors.Wrapf(err, "q.All")
}
type sStatistic struct {
TotalCount int64
PendingDeletedCount int64
}
result := map[string]apis.StatusStatistic{}
for _, s := range ret {
result[s.Status] = apis.StatusStatistic{
TotalCount: s.TotalCount,
PendingDeletedCount: s.PendingDeletedCount,
}
}
return result, nil
}
func (manager *SVirtualResourceBaseManager) FilterByHiddenSystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
q = manager.SStatusStandaloneResourceBaseManager.FilterByHiddenSystemAttributes(q, userCred, query, scope)

View File

@@ -17,6 +17,12 @@ package types
import (
"net"
"strings"
"yunion.io/x/pkg/errors"
)
const (
ErrIPMIToolNull = errors.Error("IPMI tool is null")
)
type SSHConfig struct {

View File

@@ -0,0 +1,35 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
type EFIBootMgrInfo struct {
PxeBootNum string `json:"pxe_boot_num"`
BootOrder []*EFIBootEntry `json:"boot_order"`
}
type EFIBootEntry struct {
BootNum string `json:"boot_num"`
Description string `json:"description"`
IsActive bool `json:"is_active"`
}
func (info *EFIBootMgrInfo) GetPXEEntry() *EFIBootEntry {
for _, e := range info.BootOrder {
if e.BootNum == info.PxeBootNum {
return e
}
}
return nil
}

View File

@@ -1133,6 +1133,7 @@ func (self *SCloudaccount) RegisterSAMProvider() (*SSAMLProvider, error) {
}()
sp.EntityId = options.Options.ApiServer
sp.CloudaccountId = self.Id
sp.DomainId = self.DomainId
sp.Status = api.SAML_PROVIDER_STATUS_CREATING
metadata := SamlIdpInstance().GetMetadata(self.Id).String()
sp.MetadataDocument = metadata
@@ -1199,7 +1200,7 @@ func (self *SCloudaccount) StartSyncCloudrolesTask(ctx context.Context, userCred
}
func (self *SCloudaccount) GetSAMLProviders() ([]SSAMLProvider, error) {
q := SAMLProviderManager.Query().Equals("cloudaccount_id", self.Id)
q := SAMLProviderManager.Query().Equals("cloudaccount_id", self.Id).Desc("external_id")
samls := []SSAMLProvider{}
err := db.FetchModelObjects(SAMLProviderManager, q, &samls)
if err != nil {

View File

@@ -16,7 +16,6 @@ package cloudprovider
type SSubAccount struct {
Name string
State string
Account string
HealthStatus string // 云端服务健康状态。例如欠费、项目冻结都属于不健康状态。
}

View File

@@ -58,7 +58,7 @@ func isDiskConfigStorageMatch(
adapterIsEqual := (confAdapter == nil || *confAdapter == adapter) &&
(confDriver == nil || *confDriver == driver)
log.V(10).Debugf("typeIsHybrid: %v, typeIsRotate: %v, typeIsSSD: %v, rangeIsNoneAndCountZero: %v, rangeIsNotNoneAndIndexInRange: %v, rangeIsNoneAndSmallThanCount: %v, adapterIsEqual: %v", typeIsHybrid, typeIsRotate, typeIsSSD, rangeIsNoneAndCountZero, rangeIsNotNoneAndIndexInRange, rangeIsNoneAndSmallThanCount, adapterIsEqual)
log.V(10).Debugf("Try storage: %#v, typeIsHybrid: %v, typeIsRotate: %v, typeIsSSD: %v, rangeIsNoneAndCountZero: %v, rangeIsNotNoneAndIndexInRange: %v, rangeIsNoneAndSmallThanCount: %v, adapterIsEqual: %v", *storage, typeIsHybrid, typeIsRotate, typeIsSSD, rangeIsNoneAndCountZero, rangeIsNotNoneAndIndexInRange, rangeIsNoneAndSmallThanCount, adapterIsEqual)
if (typeIsHybrid || typeIsRotate || typeIsSSD) &&
(rangeIsNoneAndCountZero || rangeIsNotNoneAndIndexInRange || rangeIsNoneAndSmallThanCount) &&
@@ -109,7 +109,11 @@ func RetrieveStorages(diskConfig *api.BaremetalDiskConfig, storages []*Baremetal
} else {
rest = append(rest, storage)
}
idx++
if confDriver == nil {
idx++
} else if *confDriver == storage.Driver {
idx++
}
}
return
}
@@ -298,10 +302,18 @@ func ExpandNoneConf(layouts []Layout) (ret []Layout) {
}
func GetLayoutRaidConfig(layouts []Layout) []*api.BaremetalDiskConfig {
return getLayoutConfig(layouts, true)
}
func GetLayoutDiskConfig(layouts []Layout) []*api.BaremetalDiskConfig {
return getLayoutConfig(layouts, false)
}
func getLayoutConfig(layouts []Layout, onlyRaidDisk bool) []*api.BaremetalDiskConfig {
var disk []*BaremetalStorage
ret := make([]*api.BaremetalDiskConfig, 0)
for _, layout := range layouts {
if layout.Conf.Conf == DISK_CONF_NONE &&
if onlyRaidDisk && layout.Conf.Conf == DISK_CONF_NONE &&
sets.NewString(DISK_DRIVER_LINUX, DISK_DRIVER_PCIE).Has(layout.Disks[0].Driver) {
continue
}
@@ -335,8 +347,8 @@ func CalculateLayout(confs []*api.BaremetalDiskConfig, storages []*BaremetalStor
noneConf, _ := ParseDiskConfig(DISK_CONF_NONE)
conf = &noneConf
}
selected, storage1 := RetrieveStorages(conf, storages)
storages = storage1
selected, restStorges := RetrieveStorages(conf, storages)
storages = restStorges
if len(selected) == 0 {
err = fmt.Errorf("Not found matched storages by config: %#v", conf)
return

View File

@@ -19,6 +19,11 @@ import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
@@ -464,7 +469,9 @@ func TestCalculateLayout(t *testing.T) {
if err != nil {
t.Fatalf("Unmarshal expectedLayoutJson err: %v", err)
}
if !reflect.DeepEqual(layout, expectedLayout) {
assert := assert.New(t)
if !assert.Equal(expectedLayout, layout) {
t.Errorf("CalculateLayout() = %v, want %v", layout, expectedLayout)
}
}
@@ -475,7 +482,7 @@ func TestCheckDisksAllocable(t *testing.T) {
"6:raid5:adapter2",
"6:raid5:adapter2",
)
bitmainConfs, err := NewBaremetalDiskConfigs("raid10:(60g,)")
bitmainConfs, err := NewBaremetalDiskConfigs("MarvelRaid:raid10:(60g,)")
if err != nil {
t.Fatalf("NewDiskConfigs err: %v", err)
}
@@ -1255,3 +1262,133 @@ func TestGetSplitSizes(t *testing.T) {
})
}
}
var (
pcieStorages = []*BaremetalStorage{
{
Driver: DISK_DRIVER_LINUX,
Rotate: true,
Size: 51200,
Adapter: 0,
Index: 0,
},
{
Driver: DISK_DRIVER_PCIE,
Rotate: false,
Size: 61440,
Adapter: 0,
Index: 0,
},
}
pcie2Storages = []*BaremetalStorage{
{
Driver: DISK_DRIVER_LINUX,
Dev: "sda",
Rotate: true,
Size: 3815447,
Adapter: 0,
Index: 0,
},
{
Driver: DISK_DRIVER_PCIE,
Dev: "nvme0n1",
Rotate: false,
Size: 1953514,
Adapter: 0,
Index: 0,
},
{
Driver: DISK_DRIVER_PCIE,
Dev: "nvme1n1",
Rotate: false,
Size: 122104,
Adapter: 0,
Index: 0,
},
}
)
func TestPCIEStoragesAllocable(t *testing.T) {
adapter0 := 0
confs := []*api.BaremetalDiskConfig{
{
Adapter: &adapter0,
Conf: DISK_CONF_NONE,
Count: 1,
Driver: DISK_DRIVER_PCIE,
Range: []int64{0},
Type: DISK_TYPE_SSD,
},
{
Adapter: &adapter0,
Conf: DISK_CONF_NONE,
Count: 1,
Driver: DISK_DRIVER_LINUX,
Range: []int64{0},
Type: DISK_TYPE_ROTATE,
},
}
layouts, err := CalculateLayout(confs, pcieStorages)
if err != nil {
t.Errorf("CalculateLayout error: %v", err)
return
}
// log.Errorf("layouts: %s", jsonutils.Marshal(layouts))
disks := []*api.DiskConfig{
{
Backend: api.STORAGE_LOCAL,
Driver: "scsi",
SizeMb: 30720,
},
{
Backend: api.STORAGE_LOCAL,
Driver: "scsi",
Fs: "ext4",
Mountpoint: "/opt",
SizeMb: -1,
},
{
Backend: api.STORAGE_LOCAL,
Driver: "scsi",
Fs: "ext4",
Mountpoint: "/data",
SizeMb: -1,
},
}
if ok := IsDisksAllocable(layouts, disks); !ok {
t.Errorf("Disk not allocable")
}
}
func Test2PCIEStoragesAllocable(t *testing.T) {
adapter0 := 0
confs := []*api.BaremetalDiskConfig{
{
Adapter: &adapter0,
Conf: DISK_CONF_NONE,
Count: 0,
Driver: DISK_DRIVER_PCIE,
Range: []int64{1},
Type: DISK_TYPE_SSD,
},
}
layouts, err := CalculateLayout(confs, pcie2Storages)
if err != nil {
t.Errorf("CalculateLayout error: %v", err)
return
}
log.Errorf("layouts: %s", jsonutils.Marshal(layouts))
disks := []*api.DiskConfig{
{
Backend: api.STORAGE_LOCAL,
Driver: "scsi",
SizeMb: -1,
},
}
if ok := IsDisksAllocable(layouts, disks); !ok {
t.Errorf("Disk not allocable")
}
}

View File

@@ -160,7 +160,7 @@ func (self *SBaremetalGuestDriver) GetNamedNetworkConfiguration(guest *models.SG
}
reuseAddr := false
hn := host.GetAttach2Network(netConfig.Network)
if hn != nil && netConfig.Address == "" && options.Options.BaremetalServerReuseHostIp {
if hn != nil && options.Options.BaremetalServerReuseHostIp {
// try to reuse host network IP address
netConfig.Address = hn.IpAddr
reuseAddr = true
@@ -345,7 +345,7 @@ func (self *SBaremetalGuestDriver) RequestStopGuestForDelete(ctx context.Context
return guest.StartGuestStopTask(ctx, task.GetUserCred(), true, false, task.GetTaskId())
}
if host != nil && !host.GetEnabled() && !purge {
return fmt.Errorf("fail to contact baremetal")
return errors.Errorf("fail to contact baremetal")
}
task.ScheduleRun(nil)
return nil

View File

@@ -94,7 +94,7 @@ func (self *SESXiGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ow
}
func (self *SESXiGuestDriver) GetDefaultSysDiskBackend() string {
return api.STORAGE_LOCAL
return ""
}
func (self *SESXiGuestDriver) ChooseHostStorage(host *models.SHost, guest *models.SGuest, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {

View File

@@ -300,6 +300,8 @@ func (manager *SCachedimageManager) GetImageById(ctx context.Context, userCred m
oSTypeOk := options.Options.NoCheckOsTypeForCachedImage || len(cachedImage.GetOSType()) > 0
if !refresh && cachedImage.GetStatus() == cloudprovider.IMAGE_STATUS_ACTIVE && oSTypeOk && !cachedImage.isRefreshSessionExpire() {
return cachedImage.GetImage()
} else if options.Options.ProhibitRefreshingCloudImage {
return cachedImage.GetImage()
} else if len(cachedImage.ExternalId) > 0 { // external image, request refresh
return cachedImage.requestRefreshExternalImage(ctx, userCred)
}
@@ -323,6 +325,8 @@ func (manager *SCachedimageManager) getImageByName(ctx context.Context, userCred
cachedImage := imgObj.(*SCachedimage)
if !refresh && cachedImage.GetStatus() == cloudprovider.IMAGE_STATUS_ACTIVE && len(cachedImage.GetOSType()) > 0 && !cachedImage.isRefreshSessionExpire() {
return cachedImage.GetImage()
} else if options.Options.ProhibitRefreshingCloudImage {
return cachedImage.GetImage()
} else if len(cachedImage.ExternalId) > 0 { // external image, request refresh
return cachedImage.requestRefreshExternalImage(ctx, userCred)
}

View File

@@ -362,7 +362,7 @@ func (manager *SCloudaccountManager) ValidateCreateData(
) (api.CloudaccountCreateInput, error) {
input, err := manager.validateCreateData(ctx, userCred, ownerId, query, input)
if err != nil {
return input, errors.Wrap(err, "validateCreateData")
return input, err
}
input.EnabledStatusInfrasResourceBaseCreateInput, err = manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusInfrasResourceBaseCreateInput)
@@ -505,8 +505,7 @@ func (manager *SCloudaccountManager) validateCreateData(
if err == cloudprovider.ErrNoSuchProvder {
return input, httperrors.NewResourceNotFoundError("no such provider %s", input.Provider)
}
//log.Debugf("ValidateCreateData %s", err.Error())
return input, httperrors.NewInputParameterError("invalid cloud account info error: %s", err.Error())
return input, httperrors.NewGeneralError(err)
}
// check accountId uniqueness
@@ -941,16 +940,14 @@ func (self *SCloudaccount) importSubAccount(ctx context.Context, userCred mcclie
return nil, isNew, cloudprovider.ErrDuplicateId
}
if providerCount == 1 {
providerObj, err := db.NewModelObject(CloudproviderManager)
if err != nil {
return nil, isNew, err
}
provider := providerObj.(*SCloudprovider)
provider := &SCloudprovider{}
provider.SetModelManager(CloudproviderManager, provider)
err = q.First(provider)
if err != nil {
return nil, isNew, err
return nil, isNew, errors.Wrapf(err, "q.First")
}
provider.markProviderConnected(ctx, userCred, subAccount.HealthStatus)
provider.updateName(ctx, userCred, subAccount.Name)
return provider, isNew, nil
}
// not found, create a new cloudprovider
@@ -2885,5 +2882,5 @@ func (self *SCloudaccount) PerformProjectMapping(ctx context.Context, userCred m
if err != nil {
return nil, err
}
return nil, refreshMapping()
return nil, refreshPmCaches()
}

View File

@@ -16,6 +16,7 @@ package models
import (
"context"
"fmt"
"sort"
"yunion.io/x/pkg/errors"
@@ -52,6 +53,14 @@ type SCloudproviderCapability struct {
Capability string `width:"18" charset:"ascii" nullable:"false" primary:"true"`
}
func (self *SCloudproviderCapability) GetId() string {
return fmt.Sprintf("%s/%s", self.CloudregionId, self.CloudproviderId)
}
func (self *SCloudproviderCapability) GetName() string {
return self.Capability
}
func (manager *SCloudproviderCapabilityManager) setCapabilities(ctx context.Context, userCred mcclient.TokenCredential, cloudproviderId string, capabilities []string) error {
return manager.setRegionCapabilities(ctx, userCred, cloudproviderId, "", capabilities)
}

View File

@@ -209,7 +209,7 @@ func (manager *SCloudproviderregionManager) QueryRelatedRegionIds(cloudAccounts
if len(cloudAccounts) > 0 {
cpq := CloudaccountManager.Query().SubQuery()
subcpq := cpq.Query(cpq.Field("id")).Filter(sqlchemy.OR(
sqlchemy.In(cpq.Field("id"), cloudAccounts),
sqlchemy.In(cpq.Field("id"), stringutils2.RemoveUtf8Strings(cloudAccounts)),
sqlchemy.In(cpq.Field("name"), cloudAccounts),
)).SubQuery()
providers := CloudproviderManager.Query().SubQuery()

View File

@@ -37,6 +37,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -52,6 +53,7 @@ type SCloudproviderManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
db.SProjectizedResourceBaseManager
SProjectMappingResourceBaseManager
SSyncableBaseResourceManager
}
@@ -108,49 +110,67 @@ type SCloudprovider struct {
// 云账号的平台信息
Provider string `width:"64" charset:"ascii" list:"domain" create:"domain_required"`
SProjectMappingResourceBase
}
type providerMapping struct {
Id string
CloudaccountId string
ProjectMappingId string
type pmCache struct {
Id string
CloudaccountId string
AccountProjectMappingId string
ManagerProjectMappingId string
}
var providerProjectMapping map[string]*providerMapping = map[string]*providerMapping{}
func (self *pmCache) GetProjectMapping() (*SProjectMapping, error) {
if len(self.ManagerProjectMappingId) > 0 {
pm, err := GetRuleMapping(self.ManagerProjectMappingId)
if err != nil {
return nil, errors.Wrapf(err, "GetRuleMapping(%s)", self.ManagerProjectMappingId)
}
if pm.Enabled.IsTrue() {
return pm, nil
}
}
if len(self.AccountProjectMappingId) > 0 {
return GetRuleMapping(self.AccountProjectMappingId)
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty project mapping id")
}
func refreshMapping() error {
q := CloudproviderManager.Query("cloudaccount_id", "id")
var pmCaches map[string]*pmCache = map[string]*pmCache{}
func refreshPmCaches() error {
q := CloudproviderManager.Query().SubQuery()
providers := q.Query(q.Field("cloudaccount_id"), q.Field("id"), q.Field("project_mapping_id").Label("manager_project_mapping_id"))
sq := CloudaccountManager.Query().SubQuery()
q = q.LeftJoin(sq, sqlchemy.Equals(q.Field("cloudaccount_id"), sq.Field("id"))).AppendField(sq.Field("project_mapping_id"))
pms := []providerMapping{}
err := q.All(&pms)
mq := providers.LeftJoin(sq, sqlchemy.Equals(q.Field("cloudaccount_id"), sq.Field("id"))).AppendField(sq.Field("project_mapping_id").Label("account_project_mapping_id"))
caches := []pmCache{}
err := mq.All(&caches)
if err != nil {
return errors.Wrapf(err, "q.All")
}
for i := range pms {
providerProjectMapping[pms[i].Id] = &pms[i]
for i := range caches {
pmCaches[caches[i].Id] = &caches[i]
}
return nil
}
func (self *providerMapping) GetCloudaccount() (*SCloudaccount, error) {
account, err := CloudaccountManager.FetchById(self.CloudaccountId)
func (self *SCloudprovider) GetProjectMapping() (*SProjectMapping, error) {
cache, err := func() (*pmCache, error) {
mp, ok := pmCaches[self.Id]
if ok {
return mp, nil
}
err := refreshPmCaches()
if err != nil {
return nil, errors.Wrapf(err, "refreshPmCaches")
}
return pmCaches[self.Id], nil
}()
if err != nil {
return nil, errors.Wrapf(err, "FetchById(%s)", self.CloudaccountId)
return nil, errors.Wrapf(err, "get project mapping cache")
}
return account.(*SCloudaccount), nil
}
func GetProviderMapping(id string) (*providerMapping, error) {
mp, ok := providerProjectMapping[id]
if ok {
return mp, nil
}
err := refreshMapping()
if err != nil {
return nil, err
}
return providerProjectMapping[id], nil
return cache.GetProjectMapping()
}
func (self *SCloudprovider) ValidateDeleteCondition(ctx context.Context) error {
@@ -976,6 +996,7 @@ func (manager *SCloudproviderManager) FetchCustomizeColumns(
stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
pmRows := manager.SProjectMappingResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
accountIds := make([]string, len(objs))
for i := range rows {
provider := objs[i].(*SCloudprovider)
@@ -985,6 +1006,7 @@ func (manager *SCloudproviderManager) FetchCustomizeColumns(
ProjectizedResourceInfo: projRows[i],
SCloudproviderUsage: provider.getUsage(),
SyncStatus2: provider.getSyncStatus2(),
ProjectMappingResourceInfo: pmRows[i],
}
capabilities, _ := CloudproviderCapabilityManager.getCapabilities(provider.Id)
if len(capabilities) > 0 {
@@ -1122,7 +1144,7 @@ func (manager *SCloudproviderManager) ListItemFilter(
if len(accountArr) > 0 {
cpq := CloudaccountManager.Query().SubQuery()
subcpq := cpq.Query(cpq.Field("id")).Filter(sqlchemy.OR(
sqlchemy.In(cpq.Field("id"), accountArr),
sqlchemy.In(cpq.Field("id"), stringutils2.RemoveUtf8Strings(accountArr)),
sqlchemy.In(cpq.Field("name"), accountArr),
)).SubQuery()
q = q.In("cloudaccount_id", subcpq)
@@ -1193,6 +1215,10 @@ func (manager *SCloudproviderManager) ListItemFilter(
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
}
q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SProjectizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SSyncableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SyncableBaseResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SSyncableBaseResourceManager.ListItemFilter")
@@ -1294,6 +1320,13 @@ func (manager *SCloudproviderManager) QueryDistinctExtraField(q *sqlchemy.SQuery
return q, nil
}
if field == "account" {
accounts := CloudaccountManager.Query("name", "id").SubQuery()
q.AppendField(accounts.Field("name", field)).Distinct()
q = q.Join(accounts, sqlchemy.Equals(q.Field("cloudaccount_id"), accounts.Field("id")))
return q, nil
}
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
@@ -1314,6 +1347,20 @@ func (provider *SCloudprovider) markProviderDisconnected(ctx context.Context, us
return provider.ClearSchedDescCache()
}
func (self *SCloudprovider) updateName(ctx context.Context, userCred mcclient.TokenCredential, name string) error {
if self.Name != name {
diff, err := db.Update(self, func() error {
self.Name = name
return nil
})
if err != nil {
return errors.Wrapf(err, "db.Update")
}
db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
}
return nil
}
func (provider *SCloudprovider) markProviderConnected(ctx context.Context, userCred mcclient.TokenCredential, healthStatus string) error {
if healthStatus != provider.HealthStatus {
diff, err := db.Update(provider, func() error {
@@ -1885,3 +1932,48 @@ func (self *SCloudprovider) SyncCallSyncCloudproviderInterVpcNetwork(ctx context
}
}
}
func (manager *SCloudproviderManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrapf(err, "SProjectizedResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SProjectMappingResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrapf(err, "SProjectMappingResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (self *SCloudprovider) AllowPerformProjectMapping(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "project-mapping")
}
// 绑定同步策略
func (self *SCloudprovider) PerformProjectMapping(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountProjectMappingInput) (jsonutils.JSONObject, error) {
if len(input.ProjectMappingId) > 0 {
_, err := validators.ValidateModel(userCred, ProjectMappingManager, &input.ProjectMappingId)
if err != nil {
return nil, err
}
if len(self.ProjectMappingId) > 0 && self.ProjectMappingId != input.ProjectMappingId {
return nil, httperrors.NewInputParameterError("cloudprovider %s has aleady bind project mapping %s", self.Name, self.ProjectMappingId)
}
}
// no changes
if self.ProjectMappingId == input.ProjectMappingId {
return nil, nil
}
_, err := db.Update(self, func() error {
self.ProjectMappingId = input.ProjectMappingId
return nil
})
if err != nil {
return nil, err
}
return nil, refreshPmCaches()
}

View File

@@ -1276,6 +1276,77 @@ func syncPublicCloudProviderInfo(
return nil
}
func getZoneForPremiseCloudRegion(ctx context.Context, userCred mcclient.TokenCredential, iregion cloudprovider.ICloudRegion) (*SZone, error) {
extHosts, err := iregion.GetIHosts()
if err != nil {
return nil, errors.Wrap(err, "unable to GetIHosts")
}
for _, extHost := range extHosts {
// onpremise host
accessIp := extHost.GetAccessIp()
if len(accessIp) == 0 {
msg := fmt.Sprintf("fail to find wire for host %s: empty host access ip", extHost.GetName())
log.Errorf(msg)
continue
}
wire, err := WireManager.GetOnPremiseWireOfIp(accessIp)
if err != nil {
msg := fmt.Sprintf("fail to find wire for host %s %s: %s", extHost.GetName(), accessIp, err)
log.Errorf(msg)
continue
}
return wire.GetZone(), nil
}
return nil, errors.Wrap(errors.ErrNotFound, "no suitable zone")
}
func syncOnPremiseCloudProviderStorage(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, iregion cloudprovider.ICloudRegion, driver cloudprovider.ICloudProvider, syncRange *SSyncRange) []sStoragecacheSyncPair {
istorages, err := iregion.GetIStorages()
if err != nil {
msg := fmt.Sprintf("GetIStorages for provider %s failed %s", provider.GetName(), err)
log.Errorf(msg)
return nil
}
zone, err := getZoneForPremiseCloudRegion(ctx, userCred, iregion)
if err != nil {
msg := fmt.Sprintf("Can't get zone for Premise cloud region %s", iregion.GetName())
log.Errorf(msg)
return nil
}
localStorages, remoteStorages, result := StorageManager.SyncStorages(ctx, userCred, provider, zone, istorages)
syncResults.Add(StorageManager, result)
msg := result.Result()
notes := fmt.Sprintf("SyncStorages for provider %s result: %s", provider.Name, msg)
log.Infof(notes)
if result.IsError() {
return nil
}
storageCachePairs := make([]sStoragecacheSyncPair, 0)
for i := 0; i < len(localStorages); i += 1 {
func() {
lockman.LockObject(ctx, &localStorages[i])
defer lockman.ReleaseObject(ctx, &localStorages[i])
if localStorages[i].Deleted {
return
}
if !isInCache(storageCachePairs, localStorages[i].StoragecacheId) {
cachePair := syncStorageCaches(ctx, userCred, provider, &localStorages[i], remoteStorages[i])
if cachePair.remote != nil && cachePair.local != nil {
storageCachePairs = append(storageCachePairs, cachePair)
}
}
if !remoteStorages[i].DisableSync() {
syncStorageDisks(ctx, userCred, syncResults, provider, driver, &localStorages[i], remoteStorages[i], syncRange)
}
}()
}
return storageCachePairs
}
func syncOnPremiseCloudProviderInfo(
ctx context.Context,
userCred mcclient.TokenCredential,
@@ -1299,8 +1370,9 @@ func syncOnPremiseCloudProviderInfo(
syncRegionBuckets(ctx, userCred, syncResults, provider, localRegion, iregion)
}
storageCachePairs := make([]sStoragecacheSyncPair, 0)
var storageCachePairs []sStoragecacheSyncPair
if cloudprovider.IsSupportCompute(driver) {
storageCachePairs = syncOnPremiseCloudProviderStorage(ctx, userCred, syncResults, provider, iregion, driver, syncRange)
ihosts, err := iregion.GetIHosts()
if err != nil {
msg := fmt.Sprintf("GetIHosts for provider %s failed %s", provider.GetName(), err)
@@ -1400,20 +1472,21 @@ func (manager *SCloudproviderregionManager) initAllRecords() {
func SyncCloudProject(userCred mcclient.TokenCredential, model db.IVirtualModel, syncOwnerId mcclient.IIdentityProvider, extModel cloudprovider.IVirtualResource, managerId string) {
newOwnerId, err := func() (mcclient.IIdentityProvider, error) {
pm, err := GetProviderMapping(managerId)
_manager, err := CloudproviderManager.FetchById(managerId)
if err != nil {
return nil, errors.Wrapf(err, "GetProviderMapping")
return nil, errors.Wrapf(err, "CloudproviderManager.FetchById(%s)", managerId)
}
if len(pm.ProjectMappingId) == 0 {
return nil, nil
}
account, err := pm.GetCloudaccount()
manager := _manager.(*SCloudprovider)
rm, err := manager.GetProjectMapping()
if err != nil {
return nil, errors.Wrapf(err, "GetCloudaccount")
if errors.Cause(err) == cloudprovider.ErrNotFound {
return nil, nil
}
return nil, errors.Wrapf(err, "GetProjectMapping")
}
rm, err := GetRuleMapping(pm.ProjectMappingId)
if err != nil {
return nil, errors.Wrapf(err, "GetRuleMapping")
account := manager.GetCloudaccount()
if account == nil {
return nil, fmt.Errorf("can not find manager %s account", manager.Name)
}
if rm != nil && rm.Enabled.Bool() {
extTags, err := extModel.GetTags()

View File

@@ -160,7 +160,7 @@ func (manager *SDBInstanceNetworkManager) SyncDBInstanceNetwork(ctx context.Cont
}
}
for i := range networks {
_, ok := remoteMap[networks[i].NetworkId]
_, ok := remoteMap[networks[i].NetworkId+networks[i].IpAddr]
if ok {
continue
}

View File

@@ -623,11 +623,43 @@ func (manager *SDBInstanceManager) FetchCustomizeColumns(
return rows
}
networks := NetworkManager.Query().SubQuery()
rdsnetworks := DBInstanceNetworkManager.Query().SubQuery()
nQ := rdsnetworks.Query(
rdsnetworks.Field("dbinstance_id"),
rdsnetworks.Field("network_id"),
networks.Field("name").Label("network_name"),
).Join(networks, sqlchemy.Equals(rdsnetworks.Field("network_id"), networks.Field("id"))).
Filter(sqlchemy.In(rdsnetworks.Field("dbinstance_id"), rdsIds))
type sRdsNetworkInfo struct {
DBInstanceId string `json:"dbinstance_id"`
NetworkName string
NetworkId string
}
rns := []sRdsNetworkInfo{}
err = nQ.All(&rns)
if err != nil {
return rows
}
rdsNetworks := map[string][]string{}
for i := range rns {
_, ok := rdsNetworks[rns[i].DBInstanceId]
if !ok {
rdsNetworks[rns[i].DBInstanceId] = []string{}
}
rdsNetworks[rns[i].DBInstanceId] = append(rdsNetworks[rns[i].DBInstanceId], rns[i].NetworkName)
}
for i := range rows {
rows[i].Zone1Name = zone1[zone1Ids[i]]
rows[i].Zone2Name = zone2[zone2Ids[i]]
rows[i].Zone3Name = zone3[zone3Ids[i]]
rows[i].Secgroups, _ = ret[rdsIds[i]]
networks, ok := rdsNetworks[rdsIds[i]]
if ok {
rows[i].Network = strings.Join(networks, ",")
}
}
return rows
@@ -1539,11 +1571,9 @@ func (self *SDBInstance) setZoneInfo() error {
return errors.Wrapf(err, "q.CountWithError")
}
if count == 0 {
q.DebugQuery()
return fmt.Errorf("failed to fetch any sku for dbinstance %s(%s)", self.Name, self.Id)
}
if count > 1 {
q.DebugQuery()
return fmt.Errorf("fetch %d skus for dbinstance %s(%s)", count, self.Name, self.Id)
}
err = q.First(&sku)

View File

@@ -325,7 +325,6 @@ func (self *SDisk) GetGuests() []SGuest {
q := query.Join(guestdisks, sqlchemy.AND(
sqlchemy.Equals(guestdisks.Field("guest_id"), query.Field("id")))).
Filter(sqlchemy.Equals(guestdisks.Field("disk_id"), self.Id))
// q.DebugQuery()
err := db.FetchModelObjects(GuestManager, q, &result)
if err != nil {
log.Errorln(err)

View File

@@ -215,7 +215,6 @@ func (manager *SDnsRecordSetManager) ValidateCreateData(ctx context.Context, use
),
),
))
policyQuery.DebugQuery()
cnt, err = policyQuery.CountWithError()
if err != nil {
return input, httperrors.NewGeneralError(err)
@@ -589,7 +588,6 @@ func (self *SDnsRecordSet) ValidateUpdateData(ctx context.Context, userCred mccl
),
),
))
policyQuery.DebugQuery()
cnt, err = policyQuery.CountWithError()
if err != nil {
return input, httperrors.NewGeneralError(err)

View File

@@ -1293,15 +1293,12 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
if host != nil && host.ManagerId == "" { // kvm
hostq := HostManager.Query().SubQuery()
wireq := WireManager.Query().SubQuery()
hostwireq := HostwireManager.Query().SubQuery()
scope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), NetworkManager.KeywordPlural(), policy.PolicyActionList)
q := NetworkManager.Query()
q = NetworkManager.FilterByOwner(q, userCred, scope)
q = q.Join(wireq, sqlchemy.Equals(wireq.Field("id"), q.Field("wire_id")))
q = q.Join(hostwireq, sqlchemy.Equals(hostwireq.Field("wire_id"), wireq.Field("id")))
q = q.Join(hostq, sqlchemy.Equals(hostq.Field("id"), host.Id))
q = q.Join(wireq, sqlchemy.Equals(wireq.Field("id"), q.Field("wire_id"))).
Filter(sqlchemy.Equals(wireq.Field("zone_id"), host.ZoneId))
q = q.Equals("server_type", api.NETWORK_TYPE_EIP)
q = q.Equals("bgp_type", bgpType)
var nets []SNetwork

View File

@@ -2152,6 +2152,19 @@ func (self *SGuest) findGuestnetworkByInfo(ipStr string, macStr string, index in
}
}
func (self *SGuest) getReuseAddr(gn *SGuestnetwork) string {
if self.GetHypervisor() != api.HYPERVISOR_BAREMETAL {
return ""
}
hostNics := self.GetHost().GetNics()
for _, hn := range hostNics {
if hn.GetMac().String() == gn.MacAddr {
return hn.IpAddr
}
}
return ""
}
// Change IPaddress of a guestnetwork
// first detach the network, then attach a network with identity mac address but different IP configurations
// TODO change IP address of a teaming NIC may fail!!
@@ -2189,7 +2202,7 @@ func (self *SGuest) PerformChangeIpaddr(ctx context.Context, userCred mcclient.T
if err != nil {
return nil, err
}
err = isValidNetworkInfo(userCred, conf)
err = isValidNetworkInfo(userCred, conf, self.getReuseAddr(gn))
if err != nil {
return nil, err
}
@@ -2338,7 +2351,7 @@ func (self *SGuest) PerformAttachnetwork(ctx context.Context, userCred mcclient.
}
var inicCnt, enicCnt int
for i := 0; i < count; i++ {
err := isValidNetworkInfo(userCred, input.Nets[i])
err := isValidNetworkInfo(userCred, input.Nets[i], "")
if err != nil {
return nil, err
}

View File

@@ -0,0 +1,150 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package models
import (
"context"
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
func (guest *SGuest) AllowPerformMigrateNetwork(
ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input api.ServerMigrateNetworkInput,
) bool {
return db.IsAdminAllowPerform(userCred, guest, "migrate-network")
}
/*
* Migrate a server from one network to another network, without change IP address
* Scenerio: the server used to be in a VPC, migrate it to a underlay network without network interruption
*/
func (guest *SGuest) PerformMigrateNetwork(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input api.ServerMigrateNetworkInput,
) (jsonutils.JSONObject, error) {
if guest.Hypervisor != api.HYPERVISOR_KVM {
return nil, errors.Wrap(httperrors.ErrNotSupported, "operation not supported for this hypervisor")
}
// first validate it against the source network, ensure the following:
// 1. the network is attach to this guest
srcModel, err := NetworkManager.FetchByIdOrName(userCred, input.Src)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "source network %s not found", input.Src)
} else {
return nil, errors.Wrap(err, "NetworkManager.FetchByIdOrName")
}
}
srcNics, err := guest.GetNetworks(srcModel.GetId())
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, errors.Wrapf(httperrors.ErrBadRequest, "server not attach to network %s", input.Src)
} else {
return nil, errors.Wrap(err, "GetNetworks")
}
}
if len(srcNics) == 0 {
return nil, errors.Wrapf(httperrors.ErrBadRequest, "server not attach to network %s", input.Src)
} else if len(srcNics) > 1 {
return nil, errors.Wrapf(httperrors.ErrNotSupported, "not support to migrate multiple interfaces")
}
srcNic := srcNics[0]
ipAddr, err := netutils.NewIPV4Addr(srcNic.IpAddr)
if err != nil {
return nil, errors.Wrapf(err, "NewIPV4Addr")
}
// next validate against the destination network, ensure the following:
// 1. the network is reachable to this server
// 1. the IP address is availalble in the new network
destModel, err := NetworkManager.FetchByIdOrName(userCred, input.Dest)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "destination network %s not found", input.Src)
} else {
return nil, errors.Wrap(err, "NetworkManager.FetchByIdOrName")
}
}
destNet := destModel.(*SNetwork)
host := guest.GetHost()
if host == nil {
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "guest is not allocated!")
}
if destNet.isOneCloudVpcNetwork() {
// vpc network should be in the same Zone
destZone := destNet.GetZone()
if destZone == nil || destZone.Id != host.ZoneId {
return nil, errors.Wrap(httperrors.ErrBadRequest, "destination overlay network not in same zone as server")
}
} else {
// underlay network should be reachable in wire
var destWire *SWire
wires := host.getAttachedWires()
for i := range wires {
if wires[i].Id == destNet.WireId {
// reachable
destWire = &wires[i]
break
}
}
if destWire == nil {
return nil, errors.Wrap(httperrors.ErrBadRequest, "destination underlay network not reachable")
}
}
lockman.LockObject(ctx, destNet)
defer lockman.ReleaseObject(ctx, destNet)
if !destNet.IsAddressInRange(ipAddr) {
return nil, errors.Wrapf(httperrors.ErrBadRequest, "ip %s not in range of destination network", ipAddr.String())
}
used, err := destNet.isAddressUsed(ipAddr.String())
if err != nil {
return nil, errors.Wrap(err, "isAddressUsed")
}
if used {
return nil, errors.Wrapf(httperrors.ErrBadRequest, "ip %s has been allocated in destination network", ipAddr.String())
}
// perform the database change
_, err = db.Update(&srcNic, func() error {
srcNic.NetworkId = destNet.Id
srcNic.MappedIpAddr = "" // reset MappedIpAddr anyway
return nil
})
if err != nil {
return nil, errors.Wrap(err, "fail to update nic network_id")
}
// synchronize the change to host, and wait it to be effective
err = guest.StartSyncTask(ctx, userCred, false, "")
if err != nil {
return nil, errors.Wrap(err, "fail to SyncTask")
}
return nil, nil
}

View File

@@ -1297,6 +1297,12 @@ func (manager *SGuestManager) validateCreateData(
dataDiskDefs := []*api.DiskConfig{}
if sku != nil && sku.AttachedDiskCount > 0 {
if sku.AttachedDiskSizeGB == 0 {
return nil, httperrors.NewInputParameterError("sku %s not indicate attached disk size", sku.Name)
}
if len(sku.AttachedDiskType) == 0 {
return nil, httperrors.NewInputParameterError("sku %s not indicate attached disk backend", sku.Name)
}
for i := 0; i < sku.AttachedDiskCount; i += 1 {
dataDisk := &api.DiskConfig{
SizeMb: sku.AttachedDiskSizeGB * 1024,
@@ -1407,7 +1413,7 @@ func (manager *SGuestManager) validateCreateData(
if err != nil {
return nil, httperrors.NewInputParameterError("parse network description error %s", err)
}
err = isValidNetworkInfo(userCred, netConfig)
err = isValidNetworkInfo(userCred, netConfig, "")
if err != nil {
return nil, err
}
@@ -2671,6 +2677,7 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
return nil, err
}
syncVirtualResourceMetadata(ctx, userCred, &guest, extVM)
SyncCloudProject(userCred, &guest, syncOwnerId, extVM, host.ManagerId)
db.OpsLog.LogEvent(&guest, db.ACT_CREATE, guest.GetShortDesc(ctx), userCred)

View File

@@ -114,7 +114,7 @@ type SHost struct {
// 物理CPU颗数
NodeCount int8 `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
// CPU描述信息
CpuDesc string `width:"64" charset:"ascii" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
CpuDesc string `width:"128" charset:"ascii" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
// CPU频率
CpuMhz int `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
// CPU缓存大小,单位KB
@@ -188,6 +188,9 @@ type SHost struct {
// IPv4地址作为么有云vpc访问外网时的网关
OvnMappedIpAddr string `width:"16" charset:"ascii" nullable:"true" list:"user"`
// UEFI详情
UefiInfo jsonutils.JSONObject `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
}
func (manager *SHostManager) GetContextManagers() [][]db.IModelManager {
@@ -1753,7 +1756,11 @@ func (self *SHost) syncWithCloudHost(ctx context.Context, userCred mcclient.Toke
self.SysInfo = extHost.GetSysInfo()
self.CpuCount = extHost.GetCpuCount()
self.NodeCount = extHost.GetNodeCount()
self.CpuDesc = extHost.GetCpuDesc()
cpuDesc := extHost.GetCpuDesc()
if len(cpuDesc) > 128 {
cpuDesc = cpuDesc[:128]
}
self.CpuDesc = cpuDesc
self.CpuMhz = extHost.GetCpuMhz()
self.MemSize = extHost.GetMemSizeMB()
self.StorageSize = extHost.GetStorageSizeMB()
@@ -1994,7 +2001,11 @@ func (manager *SHostManager) newFromCloudHost(ctx context.Context, userCred mccl
host.SysInfo = extHost.GetSysInfo()
host.CpuCount = extHost.GetCpuCount()
host.NodeCount = extHost.GetNodeCount()
host.CpuDesc = extHost.GetCpuDesc()
cpuDesc := extHost.GetCpuDesc()
if len(cpuDesc) > 128 {
cpuDesc = cpuDesc[:128]
}
host.CpuDesc = cpuDesc
host.CpuMhz = extHost.GetCpuMhz()
host.MemSize = extHost.GetMemSizeMB()
host.StorageSize = extHost.GetStorageSizeMB()
@@ -2445,7 +2456,7 @@ func (self *SHost) GetNetinterfacesWithIdAndCredential(netId string, userCred mc
if err != nil {
return nil, nil
}
if used == 0 && !reserved {
if used == 0 && !reserved && !options.Options.BaremetalServerReuseHostIp {
return nil, nil
}
matchNetIfs := make([]SNetInterface, 0)
@@ -2863,16 +2874,11 @@ func (self *SHost) getMoreDetails(ctx context.Context, out api.HostDetails, show
out.ServerIps = strings.Join(server.GetRealIPs(), ",")
}
}
netifs := self.GetNetInterfaces()
if netifs != nil && len(netifs) > 0 {
nics := self.GetNics()
if nics != nil && len(nics) > 0 {
nicInfos := []jsonutils.JSONObject{}
for i := 0; i < len(netifs); i += 1 {
nicInfo := netifs[i].getBaremetalJsonDesc()
if nicInfo == nil {
log.Errorf("netif %s get baremetal desc failed", netifs[i].GetId())
continue
}
nicInfos = append(nicInfos, nicInfo)
for i := 0; i < len(nics); i += 1 {
nicInfos = append(nicInfos, jsonutils.Marshal(nics[i]))
}
out.NicCount = len(nicInfos)
out.NicInfo = nicInfos
@@ -3527,6 +3533,10 @@ func (self *SHost) PostUpdate(ctx context.Context, userCred mcclient.TokenCreden
log.Errorf("baremetal host %s update related server %s spec error: %v", self.GetName(), guest.GetName(), err)
}
}
if err := self.startSyncConfig(ctx, userCred, "", true); err != nil {
log.Errorf("start sync host %q config after updated", self.GetName())
}
}
func (self *SHost) UpdateDnsRecords(isAdd bool) {
@@ -3932,6 +3942,25 @@ func (self *SHost) AllowPerformPrepare(ctx context.Context,
return db.IsAdminAllowPerform(userCred, self, "prepare")
}
func (self *SHost) HasBMC() bool {
ipmiInfo, _ := self.GetIpmiInfo()
if ipmiInfo.Username != "" && ipmiInfo.Password != "" {
return true
}
return false
}
func (self *SHost) IsUEFIBoot() bool {
info, _ := self.GetUEFIInfo()
if info == nil {
return false
}
if len(info.PxeBootNum) == 0 {
return false
}
return true
}
func (self *SHost) isRedfishCapable() bool {
ipmiInfo, _ := self.GetIpmiInfo()
if ipmiInfo.Verified && ipmiInfo.RedfishApi {
@@ -4274,6 +4303,7 @@ func (self *SHost) addNetif(ctx context.Context, userCred mcclient.TokenCredenti
return httperrors.NewBadRequestError("%v", err)
}
}
self.ClearSchedDescCache()
return nil
}
@@ -4424,6 +4454,9 @@ func (self *SHost) PerformDisableNetif(ctx context.Context, userCred mcclient.To
return nil, nil
}
/*
* Disable a net interface, remove IP address if assigned
*/
func (self *SHost) DisableNetif(ctx context.Context, userCred mcclient.TokenCredential, netif *SNetInterface, reserve bool) error {
bn := netif.GetBaremetalNetwork()
var ipAddr string
@@ -4586,6 +4619,7 @@ func (self *SHost) RemoveNetif(ctx context.Context, userCred mcclient.TokenCrede
}
}
}
self.ClearSchedDescCache()
return nil
}
@@ -5616,6 +5650,35 @@ func (host *SHost) GetIpmiInfo() (types.SIPMIInfo, error) {
return info, nil
}
func (host *SHost) GetNics() []*types.SNic {
netifs := host.GetNetInterfaces()
nicInfos := []*types.SNic{}
if netifs != nil && len(netifs) > 0 {
for i := 0; i < len(netifs); i += 1 {
desc := netifs[i].getBaremetalJsonDesc()
if desc == nil {
log.Errorf("netif %s get baremetal desc failed", netifs[i].GetId())
continue
}
nicInfo := new(types.SNic)
desc.Unmarshal(nicInfo)
nicInfos = append(nicInfos, nicInfo)
}
}
return nicInfos
}
func (host *SHost) GetUEFIInfo() (*types.EFIBootMgrInfo, error) {
if host.UefiInfo == nil {
return nil, nil
}
info := new(types.EFIBootMgrInfo)
if err := host.UefiInfo.Unmarshal(info); err != nil {
return nil, errors.Wrap(err, "host.UefiInfo.Unmarshal")
}
return info, nil
}
func (self *SHost) AllowGetDetailsJnlp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowGetSpec(userCred, self, "jnlp")
}
@@ -5717,7 +5780,13 @@ func (self *SHost) PerformSyncConfig(ctx context.Context, userCred mcclient.Toke
}
func (self *SHost) StartSyncConfig(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "BaremetalSyncConfigTask", self, userCred, nil, parentTaskId, "", nil)
return self.startSyncConfig(ctx, userCred, parentTaskId, false)
}
func (self *SHost) startSyncConfig(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, noStatus bool) error {
data := jsonutils.NewDict()
data.Add(jsonutils.NewBool(noStatus), "not_sync_status")
task, err := taskman.TaskManager.NewTask(ctx, "BaremetalSyncConfigTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
return err
}

View File

@@ -156,7 +156,11 @@ func (self *SHostwire) ValidateDeleteCondition(ctx context.Context) error {
return httperrors.NewInternalServerError("GetGuestnicsCount fail %s", err)
}
if cnt > 0 {
return httperrors.NewNotEmptyError("guest on the host are using networks on this wire")
// check if this is the last one
host := self.GetHost()
if len(host.getHostwiresOfId(self.WireId)) == 1 {
return httperrors.NewNotEmptyError("guest on the host are using networks on this wire")
}
}
return self.SHostJointsBase.ValidateDeleteCondition(ctx)
}
@@ -165,6 +169,29 @@ func (self *SHostwire) Delete(ctx context.Context, userCred mcclient.TokenCreden
return db.DeleteModel(ctx, userCred, self)
}
func (self *SHostwire) PreDelete(ctx context.Context, userCred mcclient.TokenCredential) {
host := self.GetHost()
if host == nil {
log.Errorf("no host found??")
return
}
netif := host.GetNetInterface(self.MacAddr)
if netif == nil {
log.Errorf("no netinterface for %s", self.MacAddr)
return
}
err := host.DisableNetif(ctx, userCred, netif, false)
if err != nil {
log.Errorf("host.DisableNetif fail %s", err)
return
}
err = netif.UnsetWire()
if err != nil {
log.Errorf("netif.UnsetWire fail %s", err)
return
}
}
func (self *SHostwire) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DetachJoint(ctx, userCred, self)
}

View File

@@ -317,11 +317,7 @@ func (man *SCachedLoadbalancerCertificateManager) newFromCloudLoadbalancerCertif
lbcert.ManagerId = provider.Id
lbcert.CloudregionId = region.Id
c := SLoadbalancerCertificate{}
q1 := LoadbalancerCertificateManager.Query().IsFalse("pending_deleted")
q1 = q1.Equals("fingerprint", extCertificate.GetFingerprint())
q1 = q1.Equals("tenant_id", provider.ProjectId)
err = q1.First(&c)
c, err := LoadbalancerCertificateManager.GetLbCertByFingerprint(provider.ProjectId, extCertificate.GetFingerprint())
if err != nil {
switch err {
case sql.ErrNoRows:
@@ -360,6 +356,23 @@ func (lbcert *SCachedLoadbalancerCertificate) SyncWithCloudLoadbalancerCertifica
if err != nil {
return err
}
// update local lb cert
localCert, err := LoadbalancerCertificateManager.GetLbCertByFingerprint(projectId.GetProjectId(), extCertificate.GetFingerprint())
if err == nil && !localCert.IsComplete() {
pkey := extCertificate.GetPrivateKey()
cert := extCertificate.GetPublickKey()
if len(pkey) > 0 && len(cert) > 0 {
_, err = db.UpdateWithLock(ctx, localCert, func() error {
localCert.Certificate = cert
localCert.PrivateKey = pkey
return nil
})
if err != nil {
log.Errorf("SyncWithCloudLoadbalancerCertificate.Update.localcert %s %s", localCert.Id, err)
}
}
}
db.OpsLog.LogSyncUpdate(lbcert, diff, userCred)
SyncCloudProject(userCred, lbcert, projectId, extCertificate, lbcert.ManagerId)

View File

@@ -478,3 +478,16 @@ func (manager *SLoadbalancerCertificateManager) GetResourceCount() ([]db.SScopeR
virts := manager.Query().IsFalse("pending_deleted")
return db.CalculateResourceCount(virts, "tenant_id")
}
func (manager *SLoadbalancerCertificateManager) GetLbCertByFingerprint(tenantId, fingerprint string) (*SLoadbalancerCertificate, error) {
c := SLoadbalancerCertificate{}
c.SetModelManager(manager, &c)
q1 := LoadbalancerCertificateManager.Query().IsFalse("pending_deleted")
q1 = q1.Equals("fingerprint", fingerprint)
q1 = q1.Equals("tenant_id", tenantId)
if err := q1.First(&c); err != nil {
return nil, err
}
return &c, nil
}

View File

@@ -78,6 +78,14 @@ func (manager *SNetInterfaceManager) FetchByMac(mac string) (*SNetInterface, err
return netif.(*SNetInterface), nil
}
func (netif *SNetInterface) UnsetWire() error {
_, err := db.Update(netif, func() error {
netif.WireId = ""
return nil
})
return err
}
func (netif *SNetInterface) GetWire() *SWire {
if len(netif.WireId) > 0 {
wireModel, _ := WireManager.FetchById(netif.WireId)

View File

@@ -60,7 +60,10 @@ type SNetworkManager struct {
var NetworkManager *SNetworkManager
func init() {
func GetNetworkManager() *SNetworkManager {
if NetworkManager != nil {
return NetworkManager
}
NetworkManager = &SNetworkManager{
SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
SNetwork{},
@@ -70,6 +73,11 @@ func init() {
),
}
NetworkManager.SetVirtualObject(NetworkManager)
return NetworkManager
}
func init() {
GetNetworkManager()
}
type SNetwork struct {
@@ -173,6 +181,59 @@ func (self *SNetwork) ValidateDeleteCondition(ctx context.Context) error {
return self.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx)
}
func (nm *SNetworkManager) jointNetworkCount(manager db.IModelManager, netIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SQuery {
q := manager.Query("network_id").In("network_id", netIds)
if filter != nil {
q = filter(q)
}
q = q.AppendField(sqlchemy.COUNT("count"))
return q
}
func (nm *SNetworkManager) GetTotalNicCount(netIds []string) (map[string]int, error) {
guestNetworkQ := nm.jointNetworkCount(GuestnetworkManager, netIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Filter(sqlchemy.IsFalse(q.Field("virtual")))
})
groupNetworkQ := nm.jointNetworkCount(GroupnetworkManager, netIds, nil)
hostNetworkQ := nm.jointNetworkCount(HostnetworkManager, netIds, nil)
lbNetworkQ := nm.jointNetworkCount(LoadbalancernetworkManager, netIds, nil)
dbInstanceNetworkQ := nm.jointNetworkCount(DBInstanceNetworkManager, netIds, nil)
eipNetworkQ := nm.jointNetworkCount(ElasticipManager, netIds, nil)
natgatewayNetworkQ := nm.jointNetworkCount(NatGatewayManager, netIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Filter(sqlchemy.IsNotEmpty(q.Field("ip_addr")))
})
reserverIpsQ := nm.jointNetworkCount(ReservedipManager, netIds, filterExpiredReservedIps)
sq := NetworkinterfacenetworkManager.Query("networkinterface_id", "network_id").In("network_id", netIds).Distinct().SubQuery()
networkInterfaceQ := NetworkInterfaceManager.Query()
networkInterfaceQ = networkInterfaceQ.Join(sq, sqlchemy.Equals(networkInterfaceQ.Field("id"), sq.Field("networkinterface_id")))
networkInterfaceQ.AppendField(sq.Field("network_id", "network_id"))
networkInterfaceQ.AppendField(sqlchemy.COUNT("count"))
networkInterfaceQ.GroupBy("network_id")
union, err := sqlchemy.UnionWithError(guestNetworkQ, groupNetworkQ, hostNetworkQ, lbNetworkQ, dbInstanceNetworkQ, eipNetworkQ, natgatewayNetworkQ, reserverIpsQ, networkInterfaceQ)
if err != nil {
return nil, err
}
networkCounts := make([]struct {
NetworkId string
Count int
}, 0)
err = union.Query().All(&networkCounts)
if err != nil {
return nil, err
}
ret := map[string]int{}
for _, nc := range networkCounts {
if len(nc.NetworkId) > 0 {
ret[nc.NetworkId] += nc.Count
}
}
return ret, nil
}
func (self *SNetwork) GetTotalNicCount() (int, error) {
count, err := self.GetAllocatedNicCount()
if err != nil {
@@ -1002,6 +1063,10 @@ func (self *SNetwork) GetFreeAddressCount() (int, error) {
return self.getFreeAddressCount()
}
func (self *SNetwork) GetTotalAddressCount() int {
return self.getIPRange().AddressCount()
}
func (self *SNetwork) getFreeAddressCount() (int, error) {
used, err := self.GetTotalNicCount()
if err != nil {
@@ -1010,7 +1075,7 @@ func (self *SNetwork) getFreeAddressCount() (int, error) {
return self.getIPRange().AddressCount() - used, nil
}
func isValidNetworkInfo(userCred mcclient.TokenCredential, netConfig *api.NetworkConfig) error {
func isValidNetworkInfo(userCred mcclient.TokenCredential, netConfig *api.NetworkConfig, reuseAddr string) error {
if len(netConfig.Network) > 0 {
netObj, err := NetworkManager.FetchByIdOrName(userCred, netConfig.Network)
if err != nil {
@@ -1043,7 +1108,7 @@ func isValidNetworkInfo(userCred mcclient.TokenCredential, netConfig *api.Networ
if err != nil {
return httperrors.NewInternalServerError("isAddressUsed fail %s", err)
}
if used {
if used && netConfig.Address != reuseAddr {
return httperrors.NewInputParameterError("Address %s has been used", netConfig.Address)
}
}
@@ -1051,10 +1116,18 @@ func isValidNetworkInfo(userCred mcclient.TokenCredential, netConfig *api.Networ
if netConfig.BwLimit > api.MAX_BANDWIDTH {
return httperrors.NewInputParameterError("Bandwidth limit cannot exceed %dMbps", api.MAX_BANDWIDTH)
}
if net.ServerType == api.NETWORK_TYPE_BAREMETAL {
// not check baremetal network free address here
// TODO: find better solution ?
return nil
}
freeCnt, err := net.getFreeAddressCount()
if err != nil {
return httperrors.NewInternalServerError("getFreeAddressCount fail %s", err)
}
if reuseAddr != "" {
freeCnt += 1
}
if freeCnt < 1 {
return httperrors.NewInputParameterError("network %s(%s) has no free addresses", net.Name, net.Id)
}

View File

@@ -141,16 +141,22 @@ func (manager *SProjectMappingManager) FetchCustomizeColumns(
mp := objs[i].(*SProjectMapping)
mpIds[i] = mp.Id
}
accounts := []struct {
type sBind struct {
Id string
Name string
ProjectMappingId string
}{}
}
accounts, managers := []sBind{}, []sBind{}
q := CloudaccountManager.Query().In("project_mapping_id", mpIds)
err := q.All(&accounts)
if err != nil {
return rows
}
q = CloudproviderManager.Query().In("project_mapping_id", mpIds)
err = q.All(&managers)
if err != nil {
return rows
}
accountMapping := map[string][]api.SProjectMappingAccount{}
for i := range accounts {
_, ok := accountMapping[accounts[i].ProjectMappingId]
@@ -163,9 +169,22 @@ func (manager *SProjectMappingManager) FetchCustomizeColumns(
}
accountMapping[accounts[i].ProjectMappingId] = append(accountMapping[accounts[i].ProjectMappingId], account)
}
managerMapping := map[string][]api.SProjectMappingAccount{}
for i := range managers {
_, ok := managerMapping[managers[i].ProjectMappingId]
if !ok {
managerMapping[managers[i].ProjectMappingId] = []api.SProjectMappingAccount{}
}
manager := api.SProjectMappingAccount{
Id: managers[i].Id,
Name: managers[i].Name,
}
managerMapping[managers[i].ProjectMappingId] = append(managerMapping[managers[i].ProjectMappingId], manager)
}
for i := range rows {
rows[i].Accounts, _ = accountMapping[mpIds[i]]
rows[i].Managers, _ = managerMapping[mpIds[i]]
}
return rows
}
@@ -236,6 +255,16 @@ func (self *SProjectMapping) GetCloudaccounts() ([]SCloudaccount, error) {
return accounts, nil
}
func (self *SProjectMapping) GetCloudproviders() ([]SCloudprovider, error) {
q := CloudproviderManager.Query().Equals("project_mapping_id", self.Id)
ret := []SCloudprovider{}
err := db.FetchModelObjects(CloudproviderManager, q, &ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (self *SProjectMapping) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
delete(projectRuleMapping, self.Id)
return self.SEnabledStatusInfrasResourceBase.Delete(ctx, userCred)
@@ -249,6 +278,13 @@ func (self *SProjectMapping) ValidateDeleteCondition(ctx context.Context) error
if len(accounts) > 0 {
return httperrors.NewNotEmptyError("project mapping has associate %d accounts", len(accounts))
}
providers, err := self.GetCloudproviders()
if err != nil {
return errors.Wrapf(err, "GetCloudproviders")
}
if len(providers) > 0 {
return httperrors.NewNotEmptyError("project mapping has associate %d cloudproviders", len(providers))
}
return self.SEnabledStatusInfrasResourceBase.ValidateDeleteCondition(ctx)
}

View File

@@ -33,6 +33,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -341,26 +342,19 @@ func (manager *SSnapshotManager) ValidateCreateData(
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.SnapshotCreateInput,
) (*jsonutils.JSONDict, error) {
for _, disk := range []string{input.Disk, input.DiskId} {
if len(disk) > 0 {
input.Disk = disk
break
}
) (api.SnapshotCreateInput, error) {
if len(input.DiskId) == 0 {
return input, httperrors.NewMissingParameterError("disk_id")
}
if len(input.Disk) == 0 {
return nil, httperrors.NewMissingParameterError("disk")
_disk, err := validators.ValidateModel(userCred, DiskManager, &input.DiskId)
if err != nil {
return input, err
}
_disk, err := DiskManager.FetchByIdOrName(userCred, input.Disk)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("failed to found disk %s", input.Disk)
}
return nil, httperrors.NewGeneralError(errors.Wrap(err, "DiskManager.FetchByIdOrName"))
}
disk := _disk.(*SDisk)
input.DiskId = disk.Id
if disk.Status != api.DISK_READY {
return input, httperrors.NewInvalidStatusError("disk %s status is not %s", disk.Name, api.DISK_READY)
}
input.DiskType = disk.DiskType
input.Size = disk.DiskSize
input.OsArch = disk.OsArch
@@ -372,38 +366,38 @@ func (manager *SSnapshotManager) ValidateCreateData(
input.ManagerId = storage.ManagerId
region := storage.GetRegion()
if region == nil {
return nil, httperrors.NewInputParameterError("failed to found region for disk's storage %s(%s)", storage.Name, storage.Id)
return input, httperrors.NewInputParameterError("failed to found region for disk's storage %s(%s)", storage.Name, storage.Id)
}
input.CloudregionId = region.Id
driver, err := storage.GetRegionDriver()
if err != nil {
return nil, errors.Wrap(err, "storage.GetRegionDriver")
return input, errors.Wrap(err, "storage.GetRegionDriver")
}
input.OutOfChain = driver.SnapshotIsOutOfChain(disk)
err = driver.ValidateCreateSnapshotData(ctx, userCred, disk, storage, &input)
if err != nil {
return nil, errors.Wrap(err, "driver.ValidateCreateSnapshotData")
return input, errors.Wrap(err, "driver.ValidateCreateSnapshotData")
}
input.VirtualResourceCreateInput, err = manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
if err != nil {
return nil, err
return input, err
}
pendingUsage := &SRegionQuota{Snapshot: 1}
keys, err := disk.GetQuotaKeys()
if err != nil {
return nil, err
return input, err
}
pendingUsage.SetKeys(keys.(SComputeResourceKeys).SRegionalCloudResourceKeys)
err = quotas.CheckSetPendingQuota(ctx, userCred, pendingUsage)
if err != nil {
return nil, err
return input, err
}
return input.JSON(input), nil
return input, nil
}
func (self *SSnapshot) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
@@ -897,7 +891,7 @@ func (self *SSnapshot) SyncWithCloudSnapshot(ctx context.Context, userCred mccli
if disk != nil {
self.SyncCloudProjectId(userCred, disk.GetOwnerId())
} else {
SyncCloudProject(userCred, self, syncOwnerId, ext, disk.GetCloudprovider().Id)
SyncCloudProject(userCred, self, syncOwnerId, ext, self.GetCloudprovider().Id)
}
return nil

Some files were not shown because too many files have changed in this diff Show More