mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 16:13:56 +08:00
Compare commits
431 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17b80d528f | ||
|
|
f0a2e020f6 | ||
|
|
2c45add982 | ||
|
|
40c020e768 | ||
|
|
372b2ff6a1 | ||
|
|
3b84c96a94 | ||
|
|
2410cea39e | ||
|
|
dc37976b50 | ||
|
|
ca844df22f | ||
|
|
5b1026f243 | ||
|
|
c6177d7228 | ||
|
|
c9f9eaa68d | ||
|
|
d70235fd11 | ||
|
|
920e841636 | ||
|
|
0abdd5195d | ||
|
|
223c72cab7 | ||
|
|
8a4f0cecd1 | ||
|
|
7dcac0a7c8 | ||
|
|
b9bb7679eb | ||
|
|
f6f75c17ec | ||
|
|
8e582878cd | ||
|
|
c8a5b58e7c | ||
|
|
43ab653d49 | ||
|
|
4082f8075c | ||
|
|
288c0d5612 | ||
|
|
7565613c4c | ||
|
|
1bd783aef8 | ||
|
|
916fa8d4b0 | ||
|
|
4058856a18 | ||
|
|
f7e90e55ab | ||
|
|
e86e95faf0 | ||
|
|
4d3ff3d332 | ||
|
|
9290e6fbd7 | ||
|
|
1396381b80 | ||
|
|
b4f4bd7502 | ||
|
|
91ec8c4487 | ||
|
|
8da9634767 | ||
|
|
41272d8073 | ||
|
|
3fbb27b8ef | ||
|
|
963550ebf4 | ||
|
|
aec0affa1b | ||
|
|
3f6db673b5 | ||
|
|
ed1e2480cc | ||
|
|
2d818c3e80 | ||
|
|
c0304519e9 | ||
|
|
5bbe39749a | ||
|
|
18c8973c6d | ||
|
|
dc819e77fc | ||
|
|
a4dd439f77 | ||
|
|
0025975b4e | ||
|
|
5b2ef0c5c0 | ||
|
|
c58c36eab8 | ||
|
|
2ffc502b2c | ||
|
|
43b963beb9 | ||
|
|
8959f6675f | ||
|
|
935d73f330 | ||
|
|
57b541c295 | ||
|
|
89e8b1fdda | ||
|
|
3706fdea49 | ||
|
|
5a34578f94 | ||
|
|
b898a169d4 | ||
|
|
91b27c21b1 | ||
|
|
4e6dd47336 | ||
|
|
5fff71781f | ||
|
|
f461726f58 | ||
|
|
53a6960478 | ||
|
|
17dec53169 | ||
|
|
306c19f5a8 | ||
|
|
4c668de666 | ||
|
|
5b9a383e43 | ||
|
|
8281dcbadc | ||
|
|
9223301f78 | ||
|
|
07aab1daea | ||
|
|
2141af918d | ||
|
|
a17ac292ea | ||
|
|
f8f773ecc8 | ||
|
|
171792d6ce | ||
|
|
052499e4eb | ||
|
|
ab33b39d9f | ||
|
|
b5bd5cbbbb | ||
|
|
f17dee9a35 | ||
|
|
58201d2aa6 | ||
|
|
59e7fd819c | ||
|
|
d5fde87fc2 | ||
|
|
fc9ca5daa3 | ||
|
|
1c5ef3961a | ||
|
|
21298fd10f | ||
|
|
980814fce0 | ||
|
|
0ec0424b7c | ||
|
|
9df734a7fe | ||
|
|
5e7b926d86 | ||
|
|
8843473697 | ||
|
|
a60084ac96 | ||
|
|
b98201c0a2 | ||
|
|
af2e8313d7 | ||
|
|
ce746b9a28 | ||
|
|
43fa5d9208 | ||
|
|
8efdcbf92c | ||
|
|
50393f47b8 | ||
|
|
ad98d01e9e | ||
|
|
ebdd4ee2a1 | ||
|
|
9a1e0d26eb | ||
|
|
8f5af535e4 | ||
|
|
58709b21a3 | ||
|
|
665dd2c0d0 | ||
|
|
911b1db6c2 | ||
|
|
e624f422d4 | ||
|
|
75360f220a | ||
|
|
f10de1e461 | ||
|
|
94455340c1 | ||
|
|
7594720f0a | ||
|
|
2a927ec7a7 | ||
|
|
57a49f8602 | ||
|
|
55fe3fa3bb | ||
|
|
ce86205aa6 | ||
|
|
cc44b3a6f2 | ||
|
|
deb7c3ea50 | ||
|
|
f4c2799815 | ||
|
|
865b6659aa | ||
|
|
94d0648f55 | ||
|
|
ba1202fe16 | ||
|
|
f5b68f0571 | ||
|
|
4038fdc2b1 | ||
|
|
395f74ffd4 | ||
|
|
509a606ec5 | ||
|
|
cafd1b9907 | ||
|
|
468a0b2d12 | ||
|
|
9f0193574e | ||
|
|
6da572d43b | ||
|
|
0c776e8797 | ||
|
|
a3943097c8 | ||
|
|
74e00b4322 | ||
|
|
e8af95d6fa | ||
|
|
2e9c42f8cb | ||
|
|
7aeb30362f | ||
|
|
47d7b434ba | ||
|
|
3ec9f8f2d4 | ||
|
|
522aada8b7 | ||
|
|
dd1c95a290 | ||
|
|
d8b9d26c6c | ||
|
|
bca3ca19e0 | ||
|
|
b9fc69576b | ||
|
|
5c67f42c66 | ||
|
|
f2b0684160 | ||
|
|
07e183ed62 | ||
|
|
468453951d | ||
|
|
6c2fed1b59 | ||
|
|
0250318839 | ||
|
|
0e774c554e | ||
|
|
e698e1df89 | ||
|
|
f3859ebf26 | ||
|
|
a1dfe36637 | ||
|
|
7459c0c1c8 | ||
|
|
8eced7fd02 | ||
|
|
188355fb1a | ||
|
|
f170d4d6b6 | ||
|
|
ea30963813 | ||
|
|
bd882c0610 | ||
|
|
912ce36abd | ||
|
|
3bf28fd41b | ||
|
|
cc292edc52 | ||
|
|
ffbb3a348f | ||
|
|
af5b1f3d3d | ||
|
|
267d83bdde | ||
|
|
72edc4b253 | ||
|
|
433e03a02a | ||
|
|
51a79c88ed | ||
|
|
bf6c114e1d | ||
|
|
479f2732e7 | ||
|
|
bab148685a | ||
|
|
6b92d1d4f0 | ||
|
|
18bedab65e | ||
|
|
e5097bcdcf | ||
|
|
86825e0235 | ||
|
|
59e52eb7f1 | ||
|
|
7692132acf | ||
|
|
236b927735 | ||
|
|
970bde5753 | ||
|
|
b9426bcd8b | ||
|
|
067b2f7fa0 | ||
|
|
4cd723d096 | ||
|
|
8c0b1b6123 | ||
|
|
6d67fc5d80 | ||
|
|
ee8db3a96a | ||
|
|
aeb73f0c26 | ||
|
|
b8499fd093 | ||
|
|
5d6851472c | ||
|
|
9e581db915 | ||
|
|
b122f1eef4 | ||
|
|
f8140a13a5 | ||
|
|
8d4d864b3d | ||
|
|
f69b97689a | ||
|
|
c86841ede0 | ||
|
|
c997eeb6f2 | ||
|
|
3019b4ae40 | ||
|
|
3c42e82278 | ||
|
|
3621719dee | ||
|
|
61236122c8 | ||
|
|
f239668975 | ||
|
|
90499535d1 | ||
|
|
5753071cc6 | ||
|
|
b508901b53 | ||
|
|
95ec3239f1 | ||
|
|
40f7da9ea1 | ||
|
|
7afa251185 | ||
|
|
9e812526c0 | ||
|
|
b6aa4cd39a | ||
|
|
7ff1264724 | ||
|
|
e53e36debf | ||
|
|
9ecd184e41 | ||
|
|
542c10bf25 | ||
|
|
57ca9d71d4 | ||
|
|
def6d0f36f | ||
|
|
69eeb1dd01 | ||
|
|
6a6ca26633 | ||
|
|
15d8c5a02a | ||
|
|
4dae72d8ab | ||
|
|
c6fcdacc52 | ||
|
|
9d82e81760 | ||
|
|
866214cf73 | ||
|
|
0a04c056e7 | ||
|
|
6b41f70c20 | ||
|
|
481fdfb656 | ||
|
|
f05468cb4b | ||
|
|
c2e2a0b246 | ||
|
|
ccaf955162 | ||
|
|
bc9ca31351 | ||
|
|
6d2f84f2e9 | ||
|
|
19791e09ce | ||
|
|
de6285b19a | ||
|
|
8d519ce2eb | ||
|
|
010523d5e4 | ||
|
|
b024ce902f | ||
|
|
9709cab7f4 | ||
|
|
7d40de6d4a | ||
|
|
0bc662d213 | ||
|
|
a1a324aec6 | ||
|
|
391ca1efba | ||
|
|
16c2e6bd2e | ||
|
|
cdc14d0ef9 | ||
|
|
9fcaf499d7 | ||
|
|
d45fc59ad6 | ||
|
|
63f1c984e3 | ||
|
|
fd03308575 | ||
|
|
b34c35ead9 | ||
|
|
4c4d4615c8 | ||
|
|
15bca887ac | ||
|
|
82ec26254d | ||
|
|
e3b3b7ab19 | ||
|
|
1f10232af0 | ||
|
|
d6c4eeef59 | ||
|
|
1aae46c8df | ||
|
|
e8955c6c7c | ||
|
|
80a1d43302 | ||
|
|
e0e8a6d91a | ||
|
|
12dc562583 | ||
|
|
1305d7a38e | ||
|
|
0e86ff6b2c | ||
|
|
f9a6a130a7 | ||
|
|
7f0f640e88 | ||
|
|
19c0825b6f | ||
|
|
3f384a1b4b | ||
|
|
fb0bb14a3c | ||
|
|
244e858760 | ||
|
|
06459b3dbb | ||
|
|
b3932c70b2 | ||
|
|
038ffa615b | ||
|
|
406d81e5dd | ||
|
|
a8953c502f | ||
|
|
aa904b972d | ||
|
|
deb1669e11 | ||
|
|
3b5e38f471 | ||
|
|
3d262bac30 | ||
|
|
2ae6c7b6ca | ||
|
|
1d58d2bac3 | ||
|
|
3c9b1a7103 | ||
|
|
a6d520608d | ||
|
|
6dbc64e830 | ||
|
|
66a4905658 | ||
|
|
675ec19689 | ||
|
|
262b934d06 | ||
|
|
7c14032fbf | ||
|
|
bad342f780 | ||
|
|
43ca3f3255 | ||
|
|
6969c21688 | ||
|
|
4a7b6f9418 | ||
|
|
e61bf0ec71 | ||
|
|
99186b3851 | ||
|
|
7ccdb1a49a | ||
|
|
3d4fc7a9fa | ||
|
|
9a28d0944a | ||
|
|
5ac6f95823 | ||
|
|
711341fd2a | ||
|
|
665ce115da | ||
|
|
6333fdba65 | ||
|
|
5f168c2831 | ||
|
|
416cfb776c | ||
|
|
784f517c6a | ||
|
|
20148fdff8 | ||
|
|
86ba641ff6 | ||
|
|
f4ddc61727 | ||
|
|
c4dc825990 | ||
|
|
85d72e029f | ||
|
|
eabcf3f370 | ||
|
|
53fc70dfce | ||
|
|
8d123bfb72 | ||
|
|
a729729bd3 | ||
|
|
7725e7947e | ||
|
|
6cd1a33e63 | ||
|
|
6b48632ad2 | ||
|
|
bd3c6cff5f | ||
|
|
a150d048a4 | ||
|
|
a25267765b | ||
|
|
16f8b30a9b | ||
|
|
50ccf939dd | ||
|
|
11a2696c87 | ||
|
|
735e749733 | ||
|
|
dd93784606 | ||
|
|
aebe35a853 | ||
|
|
39a944d5d5 | ||
|
|
dc2e87a74f | ||
|
|
c3d0b0fe1f | ||
|
|
adff20026e | ||
|
|
d1318d10e3 | ||
|
|
92ac613717 | ||
|
|
243953ba6a | ||
|
|
1dc421a6db | ||
|
|
64e1116b32 | ||
|
|
c8073bdd75 | ||
|
|
da585a7b35 | ||
|
|
da0a7c7b6e | ||
|
|
37aa862950 | ||
|
|
e55220cd11 | ||
|
|
9dfb23c281 | ||
|
|
8504d364ff | ||
|
|
6aebdcec1f | ||
|
|
aa539bff9e | ||
|
|
4a59e25772 | ||
|
|
f68601d1b9 | ||
|
|
2eeecf9e68 | ||
|
|
75a007ea19 | ||
|
|
f3ae127f2c | ||
|
|
b95b553b9b | ||
|
|
7d1f968044 | ||
|
|
7ce8ef8ab0 | ||
|
|
7c90d219b3 | ||
|
|
91141d6432 | ||
|
|
0e5459c669 | ||
|
|
fc61c093e3 | ||
|
|
b595f59ef8 | ||
|
|
07292089fa | ||
|
|
df79388ded | ||
|
|
c84dd96fff | ||
|
|
cfef1fe2a3 | ||
|
|
46517ebd13 | ||
|
|
7093cd6db2 | ||
|
|
71f0b9e2df | ||
|
|
aca33fe970 | ||
|
|
906a591f00 | ||
|
|
38f3dceeb1 | ||
|
|
c0ba43e5f1 | ||
|
|
b281cf7137 | ||
|
|
a11c14dfce | ||
|
|
0e15b63b78 | ||
|
|
824fc247a7 | ||
|
|
e1c1c0b842 | ||
|
|
3adae60e23 | ||
|
|
62b78fd43c | ||
|
|
09f44d79a4 | ||
|
|
e82392107f | ||
|
|
ed676427d2 | ||
|
|
e13885e22b | ||
|
|
bc159c7c55 | ||
|
|
bf19d87ed1 | ||
|
|
9464fbe6b2 | ||
|
|
de811130ca | ||
|
|
951e9218ce | ||
|
|
d79741dc21 | ||
|
|
d43e645ed2 | ||
|
|
170b373740 | ||
|
|
4eaa4ee9d3 | ||
|
|
2ca8d0f7e4 | ||
|
|
2ee3b2c8ab | ||
|
|
e1b2e2b508 | ||
|
|
eb4b22eaec | ||
|
|
42ec59e811 | ||
|
|
a14ab9820d | ||
|
|
94d2bc456d | ||
|
|
5cd48cec5f | ||
|
|
c039a56be1 | ||
|
|
c24235c137 | ||
|
|
85f85e394d | ||
|
|
5fdde01bea | ||
|
|
59e1534222 | ||
|
|
f6da9ad66a | ||
|
|
b55c2f7d21 | ||
|
|
24e29349bf | ||
|
|
aa7c5f1b1a | ||
|
|
a3b1b99cc4 | ||
|
|
899afd7065 | ||
|
|
2bf31dbd3a | ||
|
|
35d8cba97f | ||
|
|
8a1be0852d | ||
|
|
ef29136266 | ||
|
|
adaa7fa2ce | ||
|
|
62a4bce191 | ||
|
|
1ecbb46e59 | ||
|
|
58ca8180b6 | ||
|
|
08819e2201 | ||
|
|
b4f5f1a996 | ||
|
|
85f6e95c18 | ||
|
|
8a71e73afd | ||
|
|
407f155df1 | ||
|
|
ab0c6f1284 | ||
|
|
99d1137805 | ||
|
|
95a03ad58b | ||
|
|
659022c792 | ||
|
|
b55ac81e2a | ||
|
|
bd69dc44d7 | ||
|
|
06c303c648 | ||
|
|
15fbc035ab | ||
|
|
a25de48df9 | ||
|
|
be065e872d | ||
|
|
4c27add0ba | ||
|
|
d238540dcb | ||
|
|
fdd0bf77e6 | ||
|
|
ab5fcdad3d | ||
|
|
38d23b0739 | ||
|
|
b45811166b | ||
|
|
2ee1af186d | ||
|
|
14e537fc65 |
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -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`):
|
||||
-->
|
||||
|
||||
21
Makefile
21
Makefile
@@ -89,6 +89,9 @@ vet:
|
||||
cmd/esxi-agent: prepare_dir
|
||||
CGO_ENABLED=0 $(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@
|
||||
|
||||
cmd/fetcherfs: prepare_dir
|
||||
CGO_ENABLED=0 $(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@
|
||||
|
||||
cmd/%: prepare_dir
|
||||
$(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@
|
||||
|
||||
@@ -101,6 +104,21 @@ deb/%: cmd/%
|
||||
pkg/%: prepare_dir
|
||||
$(GO_INSTALL) $(REPO_PREFIX)/$@
|
||||
|
||||
rpm/fetcherfs: cmd/fetcherfs
|
||||
docker run --rm \
|
||||
--name docker-centos-build-fetcherfs \
|
||||
-v $(CURDIR):/data \
|
||||
registry.cn-beijing.aliyuncs.com/yunionio/centos-build:1.1-4 \
|
||||
/bin/bash -c "VERSION=3.6 /data/build/build.sh fetcherfs /opt/yunion/fetchclient/bin"
|
||||
|
||||
deb/fetcherfs: rpm/fetcherfs
|
||||
#VERSION=3.6 $(DEB_BUILD_SCRIPT) fetcherfs /opt/yunion/fetchclient/bin
|
||||
docker run --rm \
|
||||
--name docker-debian-build-fetcherfs \
|
||||
-v $(CURDIR):/data \
|
||||
registry.cn-beijing.aliyuncs.com/yunionio/debian10-base:1.0 \
|
||||
/data/build/convert_rpm2deb.sh
|
||||
|
||||
build:
|
||||
$(MAKE) $(cmdTargets)
|
||||
|
||||
@@ -268,6 +286,9 @@ image:
|
||||
|
||||
.PHONY: image
|
||||
|
||||
image-telegraf-raid-plugin:
|
||||
VERSION=release-1.6.1 ARCH=all make image telegraf-raid-plugin
|
||||
|
||||
%:
|
||||
@:
|
||||
|
||||
|
||||
6
OWNERS
6
OWNERS
@@ -4,12 +4,6 @@ reviewers:
|
||||
- ioito
|
||||
- swordqiu
|
||||
- tb365
|
||||
- wanyaoqi
|
||||
- yousong
|
||||
- zhaoxiangchun
|
||||
- zhasm
|
||||
approvers:
|
||||
- swordqiu
|
||||
- yousong
|
||||
- wanyaoqi
|
||||
- Zexi
|
||||
|
||||
18
README-CN.md
18
README-CN.md
@@ -1,12 +1,12 @@
|
||||
# Yunion OneCloud (云联融合云)
|
||||
# Yunion Cloud (云联融合云)
|
||||
|
||||
[](https://circleci.com/gh/yunionio/onecloud)
|
||||
[](https://travis-ci.org/yunionio/onecloud)
|
||||
[](https://goreportcard.com/report/github.com/yunionio/onecloud)
|
||||
[](https://circleci.com/gh/yunionio/yunioncloud)
|
||||
[](https://travis-ci.org/yunionio/yunioncloud)
|
||||
[](https://goreportcard.com/report/github.com/yunionio/yunioncloud)
|
||||
|
||||
## 什么是云联融合云?
|
||||
|
||||
云联融合云(Yunion OneCloud)是一个开源的多云平台。融合云构建在用户分布于多云基础设施之上,通过技术手段将分布于多云的异构IT资源统一管理,将多底层多云的差异向用户屏蔽,并通过网络和调度实现资源的融合与打通,在多云之上进行抽象,向用户呈现统一的使用界面和API接口,让用户就像使用一个云平台一样使用分布于多云的资源,实现一个统一的“云上之云”的云平台。
|
||||
云联融合云(Yunion Cloud)是一个开源的多云平台。融合云构建在用户分布于多云基础设施之上,通过技术手段将分布于多云的异构IT资源统一管理,将多底层多云的差异向用户屏蔽,并通过网络和调度实现资源的融合与打通,在多云之上进行抽象,向用户呈现统一的使用界面和API接口,让用户就像使用一个云平台一样使用分布于多云的资源,实现一个统一的“云上之云”的云平台。
|
||||
|
||||
鉴于企业IT基础设施的两个趋势:1. 企业使用多云基础设施,并且公有云是最主要的基础设施提供者;2. 企业应用将逐步云原生化,企业IT基础设施需要为Kubernetes优化。融合云为此架构而设计。一方面抽象管理底层的多云基础设施,另一方面为多云Kubernetes提供运行环境。融合云为企业未来的的IT基础设施架构而设计。
|
||||
|
||||
@@ -18,18 +18,18 @@
|
||||
|
||||
- 内置私有云
|
||||
|
||||
OneCloud内置完备的私有云实现,提供对用户本地IDC的虚拟机、物理机和负载均衡等资源管理。
|
||||
YunionCloud 内置完备的私有云实现,提供对用户本地IDC的虚拟机、物理机和负载均衡等资源管理。
|
||||
|
||||
- 为多云Kubernetes提供运行环境
|
||||
|
||||
OneCloud自身为运行在Kubernetes的云原生应用,并且能在多云环境部署运行Kubernetes集群。
|
||||
YunionCloud 自身为运行在Kubernetes的云原生应用,并且能在多云环境部署运行Kubernetes集群。
|
||||
|
||||
欢迎安装部署云联融合云,期待大家的反馈!
|
||||
|
||||
|
||||
## 部署
|
||||
|
||||
请参考文档 [安装部署](https://docs.yunion.io/docs/setup/) 搭建 OneCloud 集群。
|
||||
请参考文档 [安装部署](https://docs.yunion.io/docs/setup/) 搭建 YunionCloud 集群。
|
||||
|
||||
|
||||
## 文档
|
||||
@@ -51,4 +51,4 @@
|
||||
|
||||
## License
|
||||
|
||||
OneCloud 使用 Apache license 2.0. 详情请看 [LICENSE](./LICENSE) 。
|
||||
YunionCloud 使用 Apache license 2.0. 详情请看 [LICENSE](./LICENSE) 。
|
||||
|
||||
24
README.md
24
README.md
@@ -1,22 +1,22 @@
|
||||
# Yunion OneCloud
|
||||
# Yunion Cloud
|
||||
|
||||
[](https://circleci.com/gh/yunionio/onecloud)
|
||||
[](https://travis-ci.com/yunionio/onecloud/branches)
|
||||
[](https://goreportcard.com/report/github.com/yunionio/onecloud)
|
||||
[](https://circleci.com/gh/yunionio/yunioncloud)
|
||||
[](https://travis-ci.com/yunionio/yunioncloud/branches)
|
||||
[](https://goreportcard.com/report/github.com/yunionio/yunioncloud)
|
||||
|
||||
### [README in Chinese](./README-CN.md)
|
||||
|
||||
## What is Yunion OneCloud?
|
||||
## What is Yunion Cloud?
|
||||
|
||||
Yunion OneCloud is an open source unified-IaaS cloud platform.
|
||||
Yunion Cloud is an open source unified-IaaS cloud platform.
|
||||
|
||||
As its name sugguests, 'Yun' means 'cloud' in Chinese and 'Yunion OneCloud' means to unify many distinct clouds into the one that behaves like an integral cloud platform.
|
||||
As its name sugguests, 'Yun' means 'cloud' in Chinese and 'Yunion Cloud' means to unify many distinct clouds into the one that behaves like an integral cloud platform.
|
||||
|
||||
As trends show, the enterprise IT infrastructure in the future would be unavoidably heterogeneous and the public clouds should be the major infrastructure providers for many enterprises. Further, the infrastructure would most likely be prepared for the cloud-native applications running on Kubernetes. Yunion OneCloud is built to provide the cloud architecture for this scenario such that it is the middle layer between the underlying cloud infrustructures and the overlay kubernetes clusters across many clouds.
|
||||
As trends show, the enterprise IT infrastructure in the future would be unavoidably heterogeneous and the public clouds should be the major infrastructure providers for many enterprises. Further, the infrastructure would most likely be prepared for the cloud-native applications running on Kubernetes. Yunion Cloud is built to provide the cloud architecture for this scenario such that it is the middle layer between the underlying cloud infrustructures and the overlay kubernetes clusters across many clouds.
|
||||
|
||||
Many may consider Yunion OneCloud as a multi-cloud management platform (MCMP). Rather, we would view it as an IaaS platform as it does not only manage the resources and services from many clouds, but also hides the differences of underlying technologies and exposes one set of APIs that allow programatically interacting with the compute/storage/networking resources across many clouds.
|
||||
Many may consider Yunion Cloud as a multi-cloud management platform (MCMP). Rather, we would view it as an IaaS platform as it does not only manage the resources and services from many clouds, but also hides the differences of underlying technologies and exposes one set of APIs that allow programatically interacting with the compute/storage/networking resources across many clouds.
|
||||
|
||||
Yunion OneCloud is working on abstracting APIs for the following resources:
|
||||
Yunion Cloud is working on abstracting APIs for the following resources:
|
||||
|
||||
* Compute, including virtual machines, images, etc.
|
||||
* Storage, including disks, snapshots, object storages, etc.
|
||||
@@ -30,7 +30,7 @@ over the following many cloud providers:
|
||||
* Private clouds, including OpenStack, etc.
|
||||
* Public clouds, including Aliyun, AWS, Azure, Tencent Cloud, Huawei Cloud, etc.
|
||||
|
||||
You are welcome to install and try Yunion OneCloud. Looking forward to your feedback.
|
||||
You are welcome to install and try Yunion Cloud. Looking forward to your feedback.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -38,7 +38,7 @@ Please refers to [install & deployment](https://docs.yunion.io/docs/setup/) (cur
|
||||
|
||||
## Documentations
|
||||
|
||||
- [Yunion OneCloud Documents](https://docs.yunion.io/)
|
||||
- [Yunion Cloud Documents](https://docs.yunion.io/)
|
||||
|
||||
- [Swagger API](https://docs.yunion.cn/apiv2/)
|
||||
|
||||
|
||||
23
build/convert_rpm2deb.sh
Executable file
23
build/convert_rpm2deb.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
ROOT_DIR=$(dirname $(dirname $(readlink -f "$BASH_SOURCE")))
|
||||
fi
|
||||
|
||||
RPMS_DIR=$ROOT_DIR/_output/rpms
|
||||
DEBS_DIR=$ROOT_DIR/_output/debs
|
||||
|
||||
case $(uname -m) in
|
||||
x86_64)
|
||||
CURRENT_ARCH=amd64
|
||||
;;
|
||||
aarch64)
|
||||
CURRENT_ARCH=arm64
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p $DEBS_DIR && cd $DEBS_DIR
|
||||
|
||||
find $RPMS_DIR -type f -name *.rpm -exec alien --target=$CURRENT_ARCH {} \;
|
||||
@@ -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.2
|
||||
|
||||
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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
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-21080303.x86_64.rpm
|
||||
#RUN yum install -y http://192.168.122.112:8083/baremetal-pxerom-1.1.0-21080303.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>"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/climc-base:20200820
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/climc-base:20210701
|
||||
|
||||
ADD ./build/climc/root/opt /opt
|
||||
|
||||
|
||||
9
build/docker/Dockerfile.debian-base
Normal file
9
build/docker/Dockerfile.debian-base
Normal file
@@ -0,0 +1,9 @@
|
||||
# registry.cn-beijing.aliyuncs.com/yunionio/debian10-base:1.0
|
||||
|
||||
FROM debian:10
|
||||
|
||||
RUN apt update && apt install -y alien
|
||||
|
||||
RUN apt-get clean autoclean && \
|
||||
apt-get autoremove --yes && \
|
||||
rm -rf /var/lib/{apt,dpkg,cache,log}/
|
||||
20
build/docker/Makefile
Normal file
20
build/docker/Makefile
Normal file
@@ -0,0 +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:$(CLIMC_BASE_VERSION) -f ./Dockerfile.climc-base .
|
||||
|
||||
BAREMETAL_BASE_VERSION = v0.3.2
|
||||
|
||||
baremetal-base:
|
||||
$(DOCKER_BUILDX)/baremetal-base:$(BAREMETAL_BASE_VERSION) -f ./Dockerfile.baremetal-base .
|
||||
#docker push $(REGISTRY)/baremetal-base:$(BAREMETAL_BASE_VERSION)
|
||||
@@ -15,9 +15,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/ansibleserver/service"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
go procutils.WaitZombieLoop(context.TODO())
|
||||
|
||||
service.StartService()
|
||||
}
|
||||
|
||||
@@ -15,12 +15,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/service"
|
||||
"yunion.io/x/onecloud/pkg/util/atexit"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer atexit.Handle()
|
||||
|
||||
go procutils.WaitZombieLoop(context.TODO())
|
||||
|
||||
service.New().StartService()
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ func init() {
|
||||
cmd.BatchPerform("reset", new(options.ServerResetOptions))
|
||||
cmd.BatchPerform("restart", new(options.ServerRestartOptions))
|
||||
cmd.BatchPerform("purge", new(options.ServerIdsOptions))
|
||||
cmd.PrintObjectYAML().Perform("migrate-forecast", new(options.ServerMigrateForecastOptions))
|
||||
cmd.Perform("migrate", new(options.ServerMigrateOptions))
|
||||
cmd.Perform("live-migrate", new(options.ServerLiveMigrateOptions))
|
||||
cmd.Perform("modify-src-check", new(options.ServerModifySrcCheckOptions))
|
||||
@@ -84,6 +85,7 @@ func init() {
|
||||
cmd.Perform("set-auto-renew", new(options.ServerSetAutoRenew))
|
||||
cmd.Perform("save-template", new(options.ServerSaveImageOptions))
|
||||
cmd.Perform("remote-update", new(options.ServerRemoteUpdateOptions))
|
||||
cmd.Perform("migrate-network", &options.ServerMigrateNetworkOptions{})
|
||||
|
||||
cmd.Get("vnc", new(options.ServerIdOptions))
|
||||
cmd.Get("desc", new(options.ServerIdOptions))
|
||||
@@ -174,6 +176,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{}
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
|
||||
"yunion.io/x/onecloud/pkg/util/printutils"
|
||||
)
|
||||
|
||||
type ResourceCmd struct {
|
||||
@@ -32,12 +33,15 @@ type ResourceCmd struct {
|
||||
|
||||
keyword string
|
||||
prefix string
|
||||
|
||||
printObject func(jsonutils.JSONObject)
|
||||
}
|
||||
|
||||
func NewResourceCmd(manager modulebase.IBaseManager) *ResourceCmd {
|
||||
return &ResourceCmd{
|
||||
manager: manager,
|
||||
keyword: manager.GetKeyword(),
|
||||
manager: manager,
|
||||
keyword: manager.GetKeyword(),
|
||||
printObject: printObjectRecursive,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +66,30 @@ func (cmd *ResourceCmd) SetKeyword(keyword string) *ResourceCmd {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (cmd *ResourceCmd) PrintObjectYAML() *ResourceCmd {
|
||||
cmd.printObject = func(obj jsonutils.JSONObject) {
|
||||
fmt.Print(obj.YAMLString())
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (cmd *ResourceCmd) PrintObjectTable() *ResourceCmd {
|
||||
cmd.printObject = printutils.PrintJSONObject
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (cmd *ResourceCmd) PrintObjectKV() *ResourceCmd {
|
||||
cmd.printObject = printObjectFmtKv
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (cmd *ResourceCmd) PrintObjectFlattenKV() *ResourceCmd {
|
||||
cmd.printObject = func(obj jsonutils.JSONObject) {
|
||||
printObjectRecursiveEx(obj, printObjectFmtKv)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
type IOpt interface {
|
||||
Params() (jsonutils.JSONObject, error)
|
||||
}
|
||||
@@ -325,7 +353,7 @@ func (cmd ResourceCmd) PerformWithKeyword(keyword, action string, args IPerformO
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
cmd.printObject(ret)
|
||||
return nil
|
||||
}
|
||||
cmd.Run(keyword, args, callback)
|
||||
@@ -342,7 +370,7 @@ func (cmd ResourceCmd) PerformClassWithKeyword(keyword, action string, args IOpt
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
cmd.printObject(ret)
|
||||
return nil
|
||||
}
|
||||
cmd.Run(keyword, args, callback)
|
||||
@@ -363,7 +391,7 @@ func (cmd ResourceCmd) PerformClass(action string, args IOpt) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
cmd.printObject(ret)
|
||||
return nil
|
||||
}
|
||||
cmd.Run(action, args, callback)
|
||||
|
||||
@@ -24,38 +24,22 @@ 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"
|
||||
)
|
||||
|
||||
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"`
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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()
|
||||
|
||||
@@ -15,12 +15,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/esxi/service"
|
||||
"yunion.io/x/onecloud/pkg/util/atexit"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer atexit.Handle()
|
||||
|
||||
go procutils.WaitZombieLoop(context.TODO())
|
||||
|
||||
service.New().StartService()
|
||||
}
|
||||
|
||||
@@ -15,12 +15,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/image/service"
|
||||
"yunion.io/x/onecloud/pkg/util/atexit"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer atexit.Handle()
|
||||
|
||||
go procutils.WaitZombieLoop(context.TODO())
|
||||
|
||||
service.StartService()
|
||||
}
|
||||
|
||||
@@ -14,9 +14,16 @@
|
||||
|
||||
package main
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployserver"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployserver"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
go procutils.WaitZombieLoop(context.TODO())
|
||||
|
||||
deployer := deployserver.NewDeployService()
|
||||
deployer.StartService()
|
||||
}
|
||||
|
||||
@@ -15,14 +15,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/service"
|
||||
"yunion.io/x/onecloud/pkg/hostman"
|
||||
"yunion.io/x/onecloud/pkg/util/atexit"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer atexit.Handle()
|
||||
|
||||
go procutils.WaitZombieLoop(context.TODO())
|
||||
|
||||
var srv = &hostman.SHostService{}
|
||||
srv.SServiceBase = &service.SServiceBase{
|
||||
Service: srv,
|
||||
|
||||
130
cmd/rbdcli/main.go
Normal file
130
cmd/rbdcli/main.go
Normal file
@@ -0,0 +1,130 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
_ "yunion.io/x/onecloud/cmd/rbdcli/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/rbdutils"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
type BaseOptions struct {
|
||||
Help bool `help:"Show help"`
|
||||
Debug bool `help:"debug mode"`
|
||||
MonHost string `help:"Ceph Mon Host" default:"$MON_HOST"`
|
||||
Pool string `help:"Ceph pool" default:"$CEPH_POOL" metavar:"CEPH_POOL"`
|
||||
Key string `help:"Secret" default:"$CEPH_KEY" metavar:"CEPH_KEY"`
|
||||
SUBCOMMAND string `help:"rbdcli subcommand" subcommand:"true"`
|
||||
}
|
||||
|
||||
func getSubcommandParser() (*structarg.ArgumentParser, error) {
|
||||
parse, e := structarg.NewArgumentParser(&BaseOptions{},
|
||||
"rbdcli",
|
||||
"Command-line interface to rbd API.",
|
||||
`See "rbdcli help COMMAND" for help on a specific command.`)
|
||||
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
subcmd := parse.GetSubcommand()
|
||||
if subcmd == nil {
|
||||
return nil, fmt.Errorf("No subcommand argument.")
|
||||
}
|
||||
type HelpOptions struct {
|
||||
SUBCOMMAND string `help:"sub-command name"`
|
||||
}
|
||||
shellutils.R(&HelpOptions{}, "help", "Show help of a subcommand", func(args *HelpOptions) error {
|
||||
helpstr, e := subcmd.SubHelpString(args.SUBCOMMAND)
|
||||
if e != nil {
|
||||
return e
|
||||
} else {
|
||||
fmt.Print(helpstr)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
for _, v := range shellutils.CommandTable {
|
||||
_, e := subcmd.AddSubParser(v.Options, v.Command, v.Desc, v.Callback)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
func showErrorAndExit(e error) {
|
||||
fmt.Fprintf(os.Stderr, "%s", e)
|
||||
fmt.Fprintln(os.Stderr)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func newPool(opts *BaseOptions) (*rbdutils.SPool, error) {
|
||||
cli, err := rbdutils.NewCluster(opts.MonHost, opts.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pool, err := cli.GetPool(opts.Pool)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetPool(%s)", opts.Pool)
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
parser, e := getSubcommandParser()
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
e = parser.ParseArgs(os.Args[1:], false)
|
||||
options := parser.Options().(*BaseOptions)
|
||||
|
||||
if options.Help {
|
||||
fmt.Print(parser.HelpString())
|
||||
return
|
||||
}
|
||||
subcmd := parser.GetSubcommand()
|
||||
subparser := subcmd.GetSubParser()
|
||||
if e != nil {
|
||||
if subparser != nil {
|
||||
fmt.Print(subparser.Usage())
|
||||
} else {
|
||||
fmt.Print(parser.Usage())
|
||||
}
|
||||
showErrorAndExit(e)
|
||||
return
|
||||
}
|
||||
suboptions := subparser.Options()
|
||||
if options.SUBCOMMAND == "help" {
|
||||
e = subcmd.Invoke(suboptions)
|
||||
} else {
|
||||
var pool *rbdutils.SPool
|
||||
pool, e = newPool(options)
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
e = subcmd.Invoke(pool, suboptions)
|
||||
}
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
}
|
||||
51
cmd/rbdcli/shell/cluster.go
Normal file
51
cmd/rbdcli/shell/cluster.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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 shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/rbdutils"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type ClusterStatOption struct {
|
||||
}
|
||||
|
||||
shellutils.R(&ClusterStatOption{}, "cluster-stat", "Show Cluster State", func(cli *rbdutils.SPool, args *ClusterStatOption) error {
|
||||
cluster := cli.GetCluster()
|
||||
stat, err := cluster.GetClusterStats()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetClusterStats")
|
||||
}
|
||||
printObject(stat)
|
||||
return nil
|
||||
})
|
||||
|
||||
type CmdOptions struct {
|
||||
CMD string
|
||||
}
|
||||
|
||||
shellutils.R(&CmdOptions{}, "run", "Run Cluster command", func(cli *rbdutils.SPool, args *CmdOptions) error {
|
||||
ret, err := cli.GetCluster().MonCommand([]byte(args.CMD))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "MonCommand")
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
58
cmd/rbdcli/shell/pool.go
Normal file
58
cmd/rbdcli/shell/pool.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// 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 shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/rbdutils"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type PoolListOptions struct {
|
||||
}
|
||||
shellutils.R(&PoolListOptions{}, "pool-list", "List pools", func(cli *rbdutils.SPool, args *PoolListOptions) error {
|
||||
cluster := cli.GetCluster()
|
||||
pools, err := cluster.ListPools()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "ListPools")
|
||||
}
|
||||
printObject(jsonutils.Marshal(map[string][]string{"pools": pools}))
|
||||
return nil
|
||||
})
|
||||
|
||||
type PoolDeleteOptions struct {
|
||||
POOL string
|
||||
}
|
||||
|
||||
shellutils.R(&PoolDeleteOptions{}, "pool-delete", "Delete Cluster pool", func(cli *rbdutils.SPool, args *PoolDeleteOptions) error {
|
||||
return cli.GetCluster().DeletePool(args.POOL)
|
||||
})
|
||||
|
||||
type ImageListOptions struct {
|
||||
}
|
||||
|
||||
shellutils.R(&ImageListOptions{}, "image-list", "List Pool images", func(cli *rbdutils.SPool, args *ImageListOptions) error {
|
||||
images, err := cli.ListImages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(jsonutils.Marshal(map[string][]string{"images": images}))
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
25
cmd/rbdcli/shell/printutils.go
Normal file
25
cmd/rbdcli/shell/printutils.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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 shell
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/util/printutils"
|
||||
|
||||
func printList(data interface{}, total, offset, limit int, columns []string) {
|
||||
printutils.PrintInterfaceList(data, total, offset, limit, columns)
|
||||
}
|
||||
|
||||
func printObject(obj interface{}) {
|
||||
printutils.PrintInterfaceObject(obj)
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
app_common "yunion.io/x/onecloud/pkg/cloudcommon/app"
|
||||
common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
|
||||
"yunion.io/x/onecloud/pkg/util/atexit"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
"yunion.io/x/onecloud/pkg/vpcagent/options"
|
||||
_ "yunion.io/x/onecloud/pkg/vpcagent/ovn"
|
||||
"yunion.io/x/onecloud/pkg/vpcagent/worker"
|
||||
@@ -52,8 +53,12 @@ func main() {
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancelFunc := context.WithCancel(ctx)
|
||||
go procutils.WaitZombieLoop(ctx)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
ctx = context.WithValue(ctx, "wg", wg)
|
||||
wg.Add(1)
|
||||
go w.Start(ctx)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -201,7 +201,9 @@ func (apb *SAnsiblePlaybookV2) runPlaybook(ctx context.Context, userCred mcclien
|
||||
Requirements(apb.Requirements).
|
||||
Files(files).
|
||||
OutputWriter(&ansiblePlaybookOutputWriter{apb}).
|
||||
KeepTmpdir(options.Options.KeepTmpdir)
|
||||
KeepTmpdir(options.Options.KeepTmpdir).
|
||||
RolePublic(options.Options.RolePublic).
|
||||
Timeout(options.Options.Timeout)
|
||||
man.sessions.Add(apb.Id, sess)
|
||||
|
||||
// NOTE host state check? run only on online hosts and running guests, skip others
|
||||
|
||||
@@ -20,6 +20,8 @@ type AnsibleServerOptions struct {
|
||||
common_options.CommonOptions
|
||||
common_options.DBOptions
|
||||
KeepTmpdir bool `help:"Whether to save the tmp directory" json:"keep_tmpdir"`
|
||||
RolePublic bool `help:"Download and use the role of the public directory"`
|
||||
Timeout int `help:"Ansible Override the connection timeout in seconds" default:"10"`
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -140,7 +140,7 @@ func (h *AuthHandlers) GetRegionsResponse(ctx context.Context, w http.ResponseWr
|
||||
if options.Options.ReturnFullDomainList {
|
||||
filters := jsonutils.NewDict()
|
||||
if len(currentDomain) > 0 {
|
||||
filters.Add(jsonutils.NewString(currentDomain), "id")
|
||||
filters.Add(jsonutils.NewString(currentDomain), "name")
|
||||
}
|
||||
filters.Add(jsonutils.NewInt(1000), "limit")
|
||||
result, e := modules.Domains.List(s, filters)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -361,6 +361,12 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
|
||||
return
|
||||
}
|
||||
|
||||
if len(password) == 0 {
|
||||
e := httperrors.NewClientError("row %d password is empty", rowIdx)
|
||||
httperrors.JsonClientError(ctx, w, e)
|
||||
return
|
||||
}
|
||||
|
||||
domainId, ok := domains[domain]
|
||||
if !ok {
|
||||
if len(domain) == 0 {
|
||||
@@ -462,7 +468,7 @@ func (mh *MiscHandler) getDownloadsHandler(ctx context.Context, w http.ResponseW
|
||||
return
|
||||
}
|
||||
case "BatchUserRegister":
|
||||
records := [][]string{{"*用户名(user)", "用户密码(password)", "*部门/域(domain)", "*是否登录控制台(allow_web_console:true、false)"}}
|
||||
records := [][]string{{"*用户名(user)", "*用户密码(password)", "*部门/域(domain)", "*是否登录控制台(allow_web_console:true、false)"}}
|
||||
content, err = writeXlsx("users", records)
|
||||
if err != nil {
|
||||
httperrors.InternalServerError(ctx, w, "internal server error")
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -346,6 +346,14 @@ type CloudaccountPerformPrepareNetsInput struct {
|
||||
HostNumberLowerLimit *int `json:"host_number_lower_limit"`
|
||||
// enum: vcenter,datacenter,cluster
|
||||
WireLevelForVmware string `json:"wire_level_for_vmware"`
|
||||
// description: Whether to directly create the recommended network
|
||||
Create *bool `json:"create"`
|
||||
// description: It is recommended that the name of the network be the same as the native name of vmware
|
||||
OriginNetworkName *bool `json:"origin_network_name"`
|
||||
// description: Created network ip distribution strategy
|
||||
NetworkIpAllocationPolicy string `json:"network_ip_allocation_policy"`
|
||||
// description: zone of wire created
|
||||
WireZone string `json:"wire_zone"`
|
||||
}
|
||||
|
||||
type CloudaccountPerformPrepareNetsOutput struct {
|
||||
|
||||
@@ -17,8 +17,11 @@ package compute
|
||||
import (
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/util/fileutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/apis/billing"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
)
|
||||
|
||||
type DiskCreateInput struct {
|
||||
@@ -241,3 +244,16 @@ type DiskUpdateInput struct {
|
||||
// 磁盘类型
|
||||
DiskType string `json:"disk_type"`
|
||||
}
|
||||
|
||||
type DiskResizeInput struct {
|
||||
// default unit: Mb
|
||||
// example: 1024; 40G; 1024M
|
||||
Size string `json:"size"`
|
||||
}
|
||||
|
||||
func (self DiskResizeInput) SizeMb() (int, error) {
|
||||
if len(self.Size) == 0 {
|
||||
return 0, httperrors.NewMissingParameterError("size")
|
||||
}
|
||||
return fileutils.GetSizeMb(self.Size, 'M', 1024)
|
||||
}
|
||||
|
||||
@@ -171,11 +171,6 @@ const (
|
||||
CPU_MODE_HOST = "host"
|
||||
)
|
||||
|
||||
const (
|
||||
OS_ARCH_X86 = "x86"
|
||||
OS_ARCH_ARM = "arm"
|
||||
)
|
||||
|
||||
var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_BLOCK_STREAM, VM_BLOCK_STREAM_FAIL}
|
||||
var VM_CREATING_STATUS = []string{VM_CREATE_NETWORK, VM_CREATE_DISK, VM_START_DEPLOY, VM_DEPLOYING}
|
||||
|
||||
|
||||
@@ -62,9 +62,9 @@ type ServerListInput struct {
|
||||
// enum: linux,windows,vmware
|
||||
OsType []string `json:"os_type"`
|
||||
|
||||
// 对列表结果按照磁盘进行排序
|
||||
// 对列表结果按照磁盘大小进行排序
|
||||
// enum: asc,desc
|
||||
// OrderByDisk string `json:"order_by_disk"`
|
||||
OrderByDisk string `json:"order_by_disk"`
|
||||
|
||||
// 根据ip查找机器
|
||||
IpAddr string `json:"ip_addr"`
|
||||
@@ -482,3 +482,38 @@ type ServerDeleteInput struct {
|
||||
// default: false
|
||||
DeleteDisks bool
|
||||
}
|
||||
|
||||
type ServerDetachnetworkInput struct {
|
||||
// 是否保留IP地址(ip地址会进入到预留ip)
|
||||
Reserve bool `json:"reserve"`
|
||||
// 通过IP子网地址, 优先级最高
|
||||
NetId string `json:"net_id"`
|
||||
// 通过IP解绑网卡, 优先级高于mac
|
||||
IpAddr string `json:"ip_addr"`
|
||||
// 通过Mac解绑网卡, 优先级低于ip_addr
|
||||
Mac string `json:"mac"`
|
||||
}
|
||||
|
||||
type ServerMigrateForecastInput struct {
|
||||
PreferHostId string `json:"prefer_host_id"`
|
||||
// Deprecated
|
||||
PreferHost string `json:"prefer_host" yunion-deprecated-by:"prefer_host_id"`
|
||||
LiveMigrate bool `json:"live_migrate"`
|
||||
SkipCpuCheck bool `josn:"skip_cpu_check"`
|
||||
}
|
||||
|
||||
type ServerResizeDiskInput struct {
|
||||
// swagger: ignore
|
||||
Disk string `json:"disk" yunion-deprecated-by:"disk_id"`
|
||||
// 磁盘Id
|
||||
DiskId string `json:"disk_id"`
|
||||
|
||||
DiskResizeInput
|
||||
}
|
||||
|
||||
type ServerMigrateNetworkInput struct {
|
||||
// Source network Id
|
||||
Src string `json:"src"`
|
||||
// Destination network Id
|
||||
Dest string `json:"dest"`
|
||||
}
|
||||
|
||||
@@ -131,7 +131,3 @@ const (
|
||||
HOST_HEALTH_STATUS_RUNNING = "running"
|
||||
HOST_HEALTH_LOCK_PREFIX = "host-health"
|
||||
)
|
||||
|
||||
const (
|
||||
CPU_ARCH_AARCH64 = "aarch64"
|
||||
)
|
||||
|
||||
@@ -245,6 +245,9 @@ type LoadbalancerCreateInput struct {
|
||||
// 计费类型
|
||||
ChargeType string `json:"charge_type"`
|
||||
|
||||
// 出口带宽
|
||||
EgressMbps int `json:"egress_mbps"`
|
||||
|
||||
// 套餐名称
|
||||
LoadbalancerSpec string `json:"loadbalancer_spec"`
|
||||
|
||||
|
||||
@@ -140,6 +140,13 @@ type ServerSkuDetails struct {
|
||||
type ServerSkuUpdateInput struct {
|
||||
apis.EnabledStatusStandaloneResourceBaseUpdateInput
|
||||
|
||||
// 预付费状态
|
||||
// default: available
|
||||
PrepaidStatus string `json:"prepaid_status"`
|
||||
// 后付费状态
|
||||
// default: available
|
||||
PostpaidStatus string `json:"postpaid_status"`
|
||||
|
||||
InstanceTypeFamily string `json:"instance_type_family"`
|
||||
|
||||
InstanceTypeCategory string `json:"instance_type_category"`
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package apis
|
||||
|
||||
import "yunion.io/x/pkg/utils"
|
||||
|
||||
const (
|
||||
SERVICE_TYPE_IMAGE = "image"
|
||||
SERVICE_TYPE_OFFLINE_CLOUDMETA = "offlinecloudmeta"
|
||||
@@ -60,3 +62,22 @@ var (
|
||||
SERVICE_TYPE_INFLUXDB,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
OS_ARCH_X86 = "x86"
|
||||
OS_ARCH_ARM = "arm"
|
||||
|
||||
OS_ARCH_I386 = "i386"
|
||||
OS_ARCH_X86_32 = "x86_32"
|
||||
OS_ARCH_X86_64 = "x86_64"
|
||||
OS_ARCH_AARCH32 = "aarch32"
|
||||
OS_ARCH_AARCH64 = "aarch64"
|
||||
)
|
||||
|
||||
func IsARM(osArch string) bool {
|
||||
return utils.IsInStringArray(osArch, []string{
|
||||
OS_ARCH_ARM,
|
||||
OS_ARCH_AARCH32,
|
||||
OS_ARCH_AARCH64,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -40,6 +40,7 @@ var (
|
||||
"brand": "brand",
|
||||
"domain_id": "domain_id",
|
||||
"project_domain": "project_domain",
|
||||
"access_ip": "access_ip",
|
||||
}
|
||||
|
||||
RdsTags = map[string]string{
|
||||
@@ -144,4 +145,19 @@ var (
|
||||
"domain_id": "id",
|
||||
"project_domain": "name",
|
||||
}
|
||||
|
||||
StorageTags = map[string]string{
|
||||
"storage_id": "id",
|
||||
"storage_name": "name",
|
||||
"zone": "zone",
|
||||
"zone_id": "zone_id",
|
||||
"zone_ext_id": "zone_ext_id",
|
||||
"status": "status",
|
||||
"cloudregion": "cloudregion",
|
||||
"cloudregion_id": "cloudregion_id",
|
||||
"region_ext_id": "region_ext_id",
|
||||
"brand": "brand",
|
||||
"domain_id": "domain_id",
|
||||
"project_domain": "project_domain",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ const (
|
||||
METRIC_RES_TYPE_CLOUDACCOUNT = "cloudaccount"
|
||||
METRIC_RES_TYPE_TENANT = "tenant"
|
||||
METRIC_RES_TYPE_DOMAIN = "domain"
|
||||
METRIC_RES_TYPE_STORAGE = "storage"
|
||||
|
||||
METRIC_UNIT_PERCENT = "%"
|
||||
METRIC_UNIT_BPS = "bps"
|
||||
@@ -21,6 +22,7 @@ const (
|
||||
METRIC_UNIT_MS = "ms"
|
||||
METRIC_UNIT_BYTE = "byte"
|
||||
METRIC_UNIT_RMB = "RMB"
|
||||
METRIC_UNIT_MB = "Mb"
|
||||
|
||||
METRIC_DATABASE_TELE = "telegraf"
|
||||
METRIC_DATABASE_METER = "meter_db"
|
||||
@@ -38,6 +40,7 @@ var (
|
||||
METRIC_RES_TYPE_RDS: 4,
|
||||
METRIC_RES_TYPE_REDIS: 5,
|
||||
METRIC_RES_TYPE_CLOUDACCOUNT: 6,
|
||||
METRIC_RES_TYPE_STORAGE: 7,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -13,12 +13,13 @@ var (
|
||||
}
|
||||
|
||||
MEASUREMENT_TAG_KEYWORD = map[string]string{
|
||||
"host": "host",
|
||||
"guest": "vm_name",
|
||||
"redis": "redis_name",
|
||||
"rds": "rds_name",
|
||||
"oss": "oss_name",
|
||||
"cloudaccount": "cloudaccount_name",
|
||||
METRIC_RES_TYPE_HOST: "host",
|
||||
METRIC_RES_TYPE_GUEST: "vm_name",
|
||||
METRIC_RES_TYPE_REDIS: "redis_name",
|
||||
METRIC_RES_TYPE_RDS: "rds_name",
|
||||
METRIC_RES_TYPE_OSS: "oss_name",
|
||||
METRIC_RES_TYPE_CLOUDACCOUNT: "cloudaccount_name",
|
||||
METRIC_RES_TYPE_STORAGE: "storage_name",
|
||||
}
|
||||
MEASUREMENT_TAG_ID = map[string]string{
|
||||
METRIC_RES_TYPE_HOST: "host_id",
|
||||
@@ -29,6 +30,7 @@ var (
|
||||
METRIC_RES_TYPE_CLOUDACCOUNT: "cloudaccount_id",
|
||||
METRIC_RES_TYPE_TENANT: "tenant_id",
|
||||
METRIC_RES_TYPE_DOMAIN: "domain_id",
|
||||
METRIC_RES_TYPE_STORAGE: "storage_id",
|
||||
}
|
||||
AlertReduceFunc = map[string]string{
|
||||
"avg": "average value",
|
||||
|
||||
@@ -65,6 +65,7 @@ type Application struct {
|
||||
isExiting bool
|
||||
idleConnsClosed chan struct{}
|
||||
httpServer *http.Server
|
||||
slaveHttpServer *http.Server
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -464,15 +465,16 @@ func (app *Application) ListenAndServeWithoutCleanup(addr, certFile, keyFile str
|
||||
}
|
||||
|
||||
func (app *Application) ListenAndServeTLSWithCleanup2(addr string, certFile, keyFile string, onStop func(), isMaster bool) {
|
||||
httpSrv := app.initServer(addr)
|
||||
if isMaster {
|
||||
app.addDefaultHandlers()
|
||||
AddPProfHandler(app)
|
||||
}
|
||||
app.httpServer = app.initServer(addr)
|
||||
if isMaster {
|
||||
app.httpServer = httpSrv
|
||||
app.registerCleanShutdown(app.httpServer, onStop)
|
||||
} else {
|
||||
app.slaveHttpServer = httpSrv
|
||||
}
|
||||
app.listenAndServeInternal(app.httpServer, certFile, keyFile)
|
||||
app.listenAndServeInternal(httpSrv, certFile, keyFile)
|
||||
if isMaster {
|
||||
app.waitCleanShutdown()
|
||||
}
|
||||
|
||||
@@ -93,10 +93,10 @@ func (job *SStatusProbeJob) Name() string {
|
||||
|
||||
func (job *SStatusProbeJob) Do(ctx context.Context, now time.Time) error {
|
||||
bStatus := job.baremetal.GetStatus()
|
||||
if bStatus == api.BAREMETAL_READY || bStatus == api.BAREMETAL_RUNNING {
|
||||
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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1085,10 +1102,12 @@ LABEL start
|
||||
bootmode := api.BOOT_MODE_PXE
|
||||
if !isTftp {
|
||||
adminNic := b.GetAdminNic()
|
||||
var mac string
|
||||
var addr string
|
||||
var mask string
|
||||
var gateway string
|
||||
if adminNic != nil {
|
||||
mac = adminNic.GetMac().String()
|
||||
addr = adminNic.IpAddr
|
||||
mask = adminNic.GetNetMask()
|
||||
gateway = adminNic.Gateway
|
||||
@@ -1102,6 +1121,7 @@ LABEL start
|
||||
}
|
||||
}
|
||||
serverIP, _ := b.manager.Agent.GetDHCPServerIP()
|
||||
args = append(args, fmt.Sprintf("mac=%s", mac))
|
||||
args = append(args, fmt.Sprintf("dest=%s", serverIP))
|
||||
args = append(args, fmt.Sprintf("gateway=%s", gateway))
|
||||
args = append(args, fmt.Sprintf("addr=%s", addr))
|
||||
@@ -1290,11 +1310,29 @@ 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
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetAccessMac() string {
|
||||
accessMac, _ := b.desc.GetString("access_mac")
|
||||
return accessMac
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetServer() baremetaltypes.IBaremetalServer {
|
||||
b.serverLock.Lock()
|
||||
defer b.serverLock.Unlock()
|
||||
@@ -1347,6 +1385,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 +1635,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 +1644,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 +1654,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 +1683,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)
|
||||
}
|
||||
@@ -1550,6 +1829,11 @@ func (b *SBaremetalInstance) StartBaremetalResetBMCTask(userCred mcclient.TokenC
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) StartBaremetalIpmiProbeTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
|
||||
session := b.manager.GetClientSession()
|
||||
data, _ = b.manager.fetchBaremetal(session, b.GetId())
|
||||
if err := b.SaveDesc(data); err != nil {
|
||||
return err
|
||||
}
|
||||
b.StartNewTask(tasks.NewBaremetalIpmiProbeTask, userCred, taskId, data)
|
||||
return nil
|
||||
}
|
||||
@@ -1685,7 +1969,9 @@ func (b *SBaremetalInstance) SendNicInfo(nic *types.SNicDevInfo, idx int, nicTyp
|
||||
params.Add(jsonutils.NewString(nicType), "nic_type")
|
||||
}
|
||||
params.Add(jsonutils.NewInt(int64(nic.Mtu)), "mtu")
|
||||
params.Add(jsonutils.NewBool(nic.Up), "link_up")
|
||||
if nic.Up != nil {
|
||||
params.Add(jsonutils.NewBool(*nic.Up), "link_up")
|
||||
}
|
||||
if reset {
|
||||
params.Add(jsonutils.JSONTrue, "reset")
|
||||
}
|
||||
@@ -2104,6 +2390,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
|
||||
}
|
||||
|
||||
@@ -2124,7 +2419,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)
|
||||
@@ -2425,7 +2722,58 @@ func (s *SBaremetalServer) deployFs(term *ssh.Client, deployInfo *deployapi.Depl
|
||||
if strings.ToLower(rootfs.GetOs()) == "windows" {
|
||||
return nil, fmt.Errorf("Unsupported OS: %s", rootfs.GetOs())
|
||||
}
|
||||
return guestfs.DeployGuestFs(rootfs, s.desc, deployInfo)
|
||||
desc, err := deployapi.GuestDescToDeployDesc(s.desc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "To deploy desc fail")
|
||||
}
|
||||
desc, err = s.reIndexDescNics(term, desc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reIndexDescNics")
|
||||
}
|
||||
|
||||
return guestfs.DeployGuestFs(rootfs, desc, deployInfo)
|
||||
}
|
||||
|
||||
func (s *SBaremetalServer) reIndexDescNics(term *ssh.Client, desc *deployapi.GuestDesc) (*deployapi.GuestDesc, error) {
|
||||
rNics, err := tasks.GetNicsInfo(term)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Get server %s remote nics", s.GetName())
|
||||
}
|
||||
findRemoteNic := func(mac string) (int, *types.SNicDevInfo) {
|
||||
for idx, nic := range rNics {
|
||||
if nic.Mac.String() == mac {
|
||||
return idx, rNics[idx]
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
reIndexNics := func(nics []*deployapi.Nic) ([]*deployapi.Nic, error) {
|
||||
for idx, nic := range nics {
|
||||
if nic.GetNicType() == api.NIC_TYPE_IPMI {
|
||||
continue
|
||||
}
|
||||
rIdx, rNic := findRemoteNic(nic.GetMac())
|
||||
if rNic == nil {
|
||||
return nil, errors.Errorf("Not found remote nic by mac %q", nic.GetMac())
|
||||
}
|
||||
if nics[idx].Index != int32(rIdx) {
|
||||
log.Infof("Reindex nic %s index %d to %d", nics[idx].GetMac(), nics[idx].Index, rIdx)
|
||||
nics[idx].Index = int32(rIdx)
|
||||
}
|
||||
}
|
||||
return nics, nil
|
||||
}
|
||||
nics, err := reIndexNics(desc.Nics)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Reindex nics")
|
||||
}
|
||||
desc.Nics = nics
|
||||
sNics, err := reIndexNics(desc.NicsStandby)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Reindex standby nics")
|
||||
}
|
||||
desc.NicsStandby = sNics
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
func (s *SBaremetalServer) GetNics() []types.SServerNic {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -79,6 +79,7 @@ func (h *DHCPHandler) ServeDHCP(pkt dhcp.Packet, _ *net.UDPAddr, _ *net.Interfac
|
||||
if req.RelayAddr.String() == "0.0.0.0" {
|
||||
return nil, nil, fmt.Errorf("Request not from a DHCP relay, ignore mac: %s", req.ClientMac)
|
||||
}
|
||||
log.Infof("[DHCP] from relay %s packet, mac: %s", req.RelayAddr, req.ClientMac)
|
||||
conf, targets, err := req.fetchConfig(h.baremetalManager.GetClientSession())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -188,7 +189,7 @@ func (req *dhcpRequest) fetchConfig(session *mcclient.ClientSession) (*dhcp.Resp
|
||||
if len(netConf.GuestDhcp) > 0 {
|
||||
dhcpAddrList = strings.Split(netConf.GuestDhcp, ",")
|
||||
}
|
||||
log.Debugf("dhcpAddrList %s", dhcpAddrList)
|
||||
log.Debugf("find network config %#v, dhcpAddrList %s", netConf, dhcpAddrList)
|
||||
|
||||
// TODO: set cache for netConf
|
||||
if req.isPXERequest() {
|
||||
@@ -227,6 +228,7 @@ func (req *dhcpRequest) fetchConfig(session *mcclient.ClientSession) (*dhcp.Resp
|
||||
// from guestdhcp import GuestDHCPHelperTask
|
||||
// task = GuestDHCPHelperTask(self)
|
||||
// task.start()
|
||||
log.Infof("Not found baremetal by mac: %s", req.ClientMac)
|
||||
return nil, nil, nil
|
||||
}
|
||||
req.baremetalInstance = bmInstance
|
||||
@@ -328,23 +330,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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -190,7 +192,6 @@ func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremet
|
||||
|
||||
ipmiNic := &types.SNicDevInfo{
|
||||
Mac: conf.Mac,
|
||||
Up: false,
|
||||
Speed: 100,
|
||||
Mtu: 1500,
|
||||
}
|
||||
@@ -314,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 {
|
||||
@@ -328,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")
|
||||
@@ -359,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")
|
||||
@@ -369,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{})
|
||||
@@ -441,7 +447,7 @@ func (task *sBaremetalPrepareTask) updateBmInfo(cli *ssh.Client, i *baremetalPre
|
||||
}
|
||||
if o.Options.EnablePxeBoot && task.baremetal.EnablePxeBoot() {
|
||||
for _, nicInfo := range i.nicsInfo {
|
||||
if nicInfo.Mac.String() != adminNic.GetMac().String() && nicInfo.Up {
|
||||
if nicInfo.Mac.String() != adminNic.GetMac().String() && nicInfo.Up != nil && *nicInfo.Up {
|
||||
err = task.doNicWireProbe(cli, nicInfo)
|
||||
if err != nil {
|
||||
// ignore the error
|
||||
@@ -664,6 +670,10 @@ func getDMIMemInfo(cli *ssh.Client) (*types.SDMIMemInfo, error) {
|
||||
return sysutils.ParseDMIMemInfo(ret), nil
|
||||
}
|
||||
|
||||
func GetNicsInfo(cli *ssh.Client) ([]*types.SNicDevInfo, error) {
|
||||
return getNicsInfo(cli)
|
||||
}
|
||||
|
||||
func getNicsInfo(cli *ssh.Client) ([]*types.SNicDevInfo, error) {
|
||||
ret, err := cli.Run("/lib/mos/lsnic")
|
||||
if err != nil {
|
||||
|
||||
@@ -139,7 +139,7 @@ func (s *sBaremetalRegisterTask) CreateBaremetal() (string, error) {
|
||||
}
|
||||
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("name", jsonutils.NewString(strings.Replace(s.accessNic.Mac.String(), ":", "", -1)))
|
||||
params.Set("name", jsonutils.NewString(fmt.Sprintf("bm%s", strings.Replace(s.accessNic.Mac.String(), ":", "", -1))))
|
||||
params.Set("access_mac", jsonutils.NewString(s.accessNic.Mac.String()))
|
||||
params.Set("host_type", jsonutils.NewString("baremetal"))
|
||||
params.Set("is_baremetal", jsonutils.JSONTrue)
|
||||
@@ -245,8 +245,9 @@ func (s *sBaremetalRegisterTask) updateIpmiInfo(cli *ssh.Client) {
|
||||
ipmitool.SetDellIPMILanPortShared(ipmiTool)
|
||||
}
|
||||
}
|
||||
up := true
|
||||
var nic = &types.SNicDevInfo{
|
||||
Up: true,
|
||||
Up: &up,
|
||||
Speed: 100,
|
||||
Mtu: 1500,
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -157,9 +157,10 @@ func (self *SBaremetalIpmiProbeTask) sendIpmiNicInfo(lanConf *types.SIPMILanConf
|
||||
if speed <= 0 {
|
||||
speed = 100
|
||||
}
|
||||
up := true
|
||||
ipmiNic := &types.SNicDevInfo{
|
||||
Mac: lanConf.Mac,
|
||||
Up: true,
|
||||
Up: &up,
|
||||
Speed: speed,
|
||||
Mtu: 1500,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package ipmitool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
@@ -115,21 +116,21 @@ func (ipmi *LanPlusIPMI) GetMode() string {
|
||||
return "rmcp"
|
||||
}
|
||||
|
||||
func (ipmi *LanPlusIPMI) GetCommand(args ...string) *procutils.Command {
|
||||
func (ipmi *LanPlusIPMI) GetCommand(args ...string) (*procutils.Command, context.CancelFunc) {
|
||||
nArgs := []string{
|
||||
"--signal=KILL",
|
||||
fmt.Sprintf("%s", ipmi.GetDefaultTimeout()),
|
||||
"ipmitool", "-I", "lanplus", "-H", ipmi.host,
|
||||
"-I", "lanplus", "-H", ipmi.host,
|
||||
"-p", fmt.Sprintf("%d", ipmi.port),
|
||||
"-U", ipmi.user,
|
||||
"-P", ipmi.password,
|
||||
}
|
||||
nArgs = append(nArgs, args...)
|
||||
return procutils.NewCommand("timeout", nArgs...)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), ipmi.GetDefaultTimeout())
|
||||
return procutils.NewCommandContext(ctx, "ipmitool", nArgs...), cancel
|
||||
}
|
||||
|
||||
func (ipmi *LanPlusIPMI) ExecuteCommand(args ...string) ([]string, error) {
|
||||
cmd := ipmi.GetCommand(args...)
|
||||
cmd, cancel := ipmi.GetCommand(args...)
|
||||
defer cancel()
|
||||
log.Debugf("[LanPlusIPMI] execute command: %s", cmd.String())
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
@@ -550,7 +551,7 @@ func DoReboot(exector IPMIExecutor) error {
|
||||
if status == types.POWER_STATUS_OFF {
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +561,7 @@ func DoReboot(exector IPMIExecutor) error {
|
||||
if err := DoPowerOn(exector); err != nil {
|
||||
log.Errorf("DoReboot %d tries to power on: %v", tried, err)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(10 * time.Second)
|
||||
status, err = GetChassisPowerStatus(exector)
|
||||
if err != nil {
|
||||
log.Errorf("DoReboot %d tries to get power status: %v", tried, err)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,12 @@ func (dev *MegaRaidPhyDev) parseLine(line string) bool {
|
||||
dev.Status = "online"
|
||||
} else if val == "Rebuild" {
|
||||
dev.Status = "rebuild"
|
||||
} else if strings.Contains(strings.ToLower(val), "hotspare") {
|
||||
dev.Status = "hotspare"
|
||||
} else if strings.Contains(strings.ToLower(val), "copyback") {
|
||||
dev.Status = "copyback"
|
||||
} else if strings.Contains(strings.ToLower(val), "unconfigured(good)") {
|
||||
dev.Status = "unconfigured_good"
|
||||
} else {
|
||||
dev.Status = "offline"
|
||||
}
|
||||
@@ -609,6 +615,7 @@ func (adapter *MegaRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage
|
||||
|
||||
type StorcliAdaptor struct {
|
||||
Controller int
|
||||
isSNEmpty bool
|
||||
sn string
|
||||
name string
|
||||
}
|
||||
@@ -616,6 +623,7 @@ type StorcliAdaptor struct {
|
||||
func newStorcliAdaptor() *StorcliAdaptor {
|
||||
return &StorcliAdaptor{
|
||||
Controller: -1,
|
||||
isSNEmpty: false,
|
||||
sn: "",
|
||||
name: "",
|
||||
}
|
||||
@@ -626,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='`)
|
||||
|
||||
118
pkg/baremetal/utils/raid/megactl/megactl_test.go
Normal file
118
pkg/baremetal/utils/raid/megactl/megactl_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
1
pkg/baremetal/utils/uefi/doc.go
Normal file
1
pkg/baremetal/utils/uefi/doc.go
Normal file
@@ -0,0 +1 @@
|
||||
package uefi // import "yunion.io/x/onecloud/pkg/baremetal/utils/uefi"
|
||||
478
pkg/baremetal/utils/uefi/uefi.go
Normal file
478
pkg/baremetal/utils/uefi/uefi.go
Normal 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
|
||||
}
|
||||
316
pkg/baremetal/utils/uefi/uefi_test.go
Normal file
316
pkg/baremetal/utils/uefi/uefi_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func ServeForeverExtended(app *appsrv.Application, options *common_options.BaseO
|
||||
if options.EnableSsl {
|
||||
proto = "https"
|
||||
}
|
||||
log.Infof("Start listen on %s://%s", proto, addr)
|
||||
log.Infof("Start listen on %s://%s, isMaster: %v", proto, addr, isMaster)
|
||||
var certfile string
|
||||
var sslfile string
|
||||
if options.EnableSsl {
|
||||
|
||||
@@ -17,6 +17,7 @@ package cronman
|
||||
import (
|
||||
"container/heap"
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -393,7 +394,7 @@ func (job *SCronJob) runJobInWorker(isStart bool) {
|
||||
log.Debugf("Cron job: %s started", job.Name)
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_APPNAME, "Cron-Service")
|
||||
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_TASKNAME, job.Name)
|
||||
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_TASKNAME, fmt.Sprintf("%s-%d", job.Name, time.Now().Unix()))
|
||||
userCred := DefaultAdminSessionGenerator()
|
||||
job.job(ctx, userCred, isStart)
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
@@ -86,25 +88,45 @@ func InitDB(options *common_options.DBOptions) {
|
||||
}
|
||||
// lm := lockman.NewNoopLockManager()
|
||||
|
||||
if len(options.EtcdEndpoints) != 0 {
|
||||
log.Infof("using etcd as resource informer backend")
|
||||
tlsCfg, err := options.GetEtcdTLSConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("get etcd informer backend tls config err: %v", err)
|
||||
startInitInformer(options)
|
||||
}
|
||||
|
||||
// startInitInformer starts goroutine init informer backend
|
||||
func startInitInformer(options *common_options.DBOptions) {
|
||||
go func() {
|
||||
if len(options.EtcdEndpoints) == 0 {
|
||||
return
|
||||
}
|
||||
informerBackend, err := informer.NewEtcdBackend(&etcd.SEtcdOptions{
|
||||
EtcdEndpoint: options.EtcdEndpoints,
|
||||
EtcdTimeoutSeconds: 5,
|
||||
EtcdRequestTimeoutSeconds: 2,
|
||||
EtcdLeaseExpireSeconds: 5,
|
||||
EtcdEnabldSsl: options.EtcdUseTLS,
|
||||
TLSConfig: tlsCfg,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
log.Fatalf("new etcd informer backend error: %v", err)
|
||||
for {
|
||||
log.Infof("using etcd as resource informer backend")
|
||||
if err := initInformer(options); err != nil {
|
||||
log.Errorf("Init informer error: %v", err)
|
||||
time.Sleep(10 * time.Second)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
informer.Init(informerBackend)
|
||||
}()
|
||||
}
|
||||
|
||||
func initInformer(options *common_options.DBOptions) error {
|
||||
tlsCfg, err := options.GetEtcdTLSConfig()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get etcd informer backend tls config")
|
||||
}
|
||||
informerBackend, err := informer.NewEtcdBackend(&etcd.SEtcdOptions{
|
||||
EtcdEndpoint: options.EtcdEndpoints,
|
||||
EtcdTimeoutSeconds: 5,
|
||||
EtcdRequestTimeoutSeconds: 2,
|
||||
EtcdLeaseExpireSeconds: 5,
|
||||
EtcdEnabldSsl: options.EtcdUseTLS,
|
||||
TLSConfig: tlsCfg,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "new etcd informer backend")
|
||||
}
|
||||
informer.Init(informerBackend)
|
||||
return nil
|
||||
}
|
||||
|
||||
func CloseDB() {
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
@@ -40,11 +39,16 @@ func (manager *SMultiArchResourceBaseManager) ListItemFilter(
|
||||
query apis.MultiArchResourceBaseListInput,
|
||||
) (*sqlchemy.SQuery, error) {
|
||||
if len(query.OsArch) > 0 {
|
||||
if query.OsArch == compute.OS_ARCH_X86 {
|
||||
if query.OsArch == apis.OS_ARCH_X86 {
|
||||
q = q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Startswith(q.Field("os_arch"), query.OsArch),
|
||||
sqlchemy.IsNullOrEmpty(q.Field("os_arch")),
|
||||
))
|
||||
} else if query.OsArch == apis.OS_ARCH_ARM {
|
||||
q = q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Startswith(q.Field("os_arch"), query.OsArch),
|
||||
sqlchemy.Equals(q.Field("os_arch"), apis.OS_ARCH_AARCH64),
|
||||
))
|
||||
} else {
|
||||
q = q.Startswith("os_arch", query.OsArch)
|
||||
}
|
||||
|
||||
@@ -932,11 +932,7 @@ func (dispatcher *DBModelDispatcher) tryGetModelProperty(ctx context.Context, pr
|
||||
}
|
||||
|
||||
if consts.IsRbacEnabled() {
|
||||
ownerId, err := fetchOwnerId(ctx, dispatcher.modelManager, userCred, query)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
err = isClassRbacAllowed(dispatcher.modelManager, userCred, ownerId, policy.PolicyActionList, property)
|
||||
_, _, err := FetchCheckQueryOwnerScope(ctx, userCred, query, dispatcher.modelManager, policy.PolicyActionList, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/util/compare"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/i18n"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
@@ -177,8 +176,10 @@ func (manager *SI18nManager) RemoveI18ns(ctx context.Context, userCred mcclient.
|
||||
}
|
||||
|
||||
func (manager *SI18nManager) SyncI18ns(ctx context.Context, userCred mcclient.TokenCredential, model IModel, table IModelI18nTable) ([]SI18n, []IModelI18nEntry, compare.SyncResult) {
|
||||
lockman.LockClass(ctx, manager, "")
|
||||
defer lockman.ReleaseClass(ctx, manager, "")
|
||||
//// No need to lock SI18nManager, the resources has been lock in the upper layer - QIU Jian, 20210405
|
||||
// lockman.LockClass(ctx, manager, "")
|
||||
// defer lockman.ReleaseClass(ctx, manager, "")
|
||||
|
||||
syncResult := compare.SyncResult{}
|
||||
|
||||
extItems := manager.getExternalI18nItems(ctx, table)
|
||||
@@ -257,7 +258,7 @@ func (manager *SI18nManager) newFromI18n(ctx context.Context, userCred mcclient.
|
||||
}
|
||||
|
||||
func (self *SI18n) updateFromI18n(ctx context.Context, userCred mcclient.TokenCredential, entry IModelI18nEntry) error {
|
||||
_, err := UpdateWithLock(ctx, self, func() error {
|
||||
_, err := Update(self, func() error {
|
||||
self.KeyValue = entry.GetKeyValue()
|
||||
self.Cn = entry.Lookup(i18n.I18N_TAG_CHINESE)
|
||||
self.En = entry.Lookup(i18n.I18N_TAG_ENGLISH)
|
||||
@@ -273,8 +274,8 @@ func (self *SI18n) updateFromI18n(ctx context.Context, userCred mcclient.TokenCr
|
||||
}
|
||||
|
||||
func (self *SI18n) removeI18n(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
lockman.LockObject(ctx, self)
|
||||
defer lockman.ReleaseObject(ctx, self)
|
||||
// lockman.LockObject(ctx, self)
|
||||
// defer lockman.ReleaseObject(ctx, self)
|
||||
|
||||
err := self.Delete(ctx, userCred)
|
||||
return err
|
||||
|
||||
@@ -31,6 +31,7 @@ const (
|
||||
}*/
|
||||
|
||||
type SInMemoryLockRecord struct {
|
||||
key string
|
||||
lock *sync.Mutex
|
||||
cond *sync.Cond
|
||||
holder context.Context
|
||||
@@ -45,6 +46,11 @@ func newInMemoryLockRecord(ctx context.Context) *SInMemoryLockRecord {
|
||||
return &rec
|
||||
}
|
||||
|
||||
func (rec *SInMemoryLockRecord) fatalf(fmtStr string, args ...interface{}) {
|
||||
debug.PrintStack()
|
||||
log.Fatalf(fmtStr, args...)
|
||||
}
|
||||
|
||||
func (rec *SInMemoryLockRecord) lockContext(ctx context.Context) {
|
||||
rec.lock.Lock()
|
||||
defer rec.lock.Unlock()
|
||||
@@ -56,18 +62,17 @@ func (rec *SInMemoryLockRecord) lockContext(ctx context.Context) {
|
||||
}
|
||||
|
||||
if debug_log {
|
||||
log.Debugf("rec.hold=[%p] ctx=[%p] %v", rec.holder, ctx, rec.holder == ctx)
|
||||
log.Debugf("rec.hold=[%p] ctx=[%p] %v key=[%s]", rec.holder, ctx, rec.holder == ctx, rec.key)
|
||||
}
|
||||
|
||||
if rec.holder == ctx {
|
||||
rec.depth += 1
|
||||
if debug_log {
|
||||
log.Infof("lockContext: same ctx, depth: %d [%p]", rec.depth, rec.holder)
|
||||
log.Infof("lockContext: same ctx, depth: %d [%p] key=[%s]", rec.depth, rec.holder, rec.key)
|
||||
}
|
||||
if rec.depth > 32 {
|
||||
// XXX MUST BE BUG ???
|
||||
debug.PrintStack()
|
||||
panic("Too many recursive locks!!!")
|
||||
rec.fatalf("Too many recursive locks!!! key=[%s]", rec.key)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -76,7 +81,7 @@ func (rec *SInMemoryLockRecord) lockContext(ctx context.Context) {
|
||||
rec.waiter.Enum(func(ele interface{}) {
|
||||
electx := ele.(context.Context)
|
||||
if electx == ctx {
|
||||
log.Fatalf("try to lock from a waiter context????")
|
||||
rec.fatalf("try to lock from a waiter context???? key=[%s]", rec.key)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -84,7 +89,7 @@ func (rec *SInMemoryLockRecord) lockContext(ctx context.Context) {
|
||||
|
||||
if debug_log {
|
||||
log.Debugf("waiter size %d after push", rec.waiter.Len())
|
||||
log.Debugf("Start to wait ... [%p]", ctx)
|
||||
log.Debugf("Start to wait ... [%p] key=[%s]", ctx, rec.key)
|
||||
}
|
||||
|
||||
for rec.holder != nil {
|
||||
@@ -92,13 +97,13 @@ func (rec *SInMemoryLockRecord) lockContext(ctx context.Context) {
|
||||
}
|
||||
|
||||
if debug_log {
|
||||
log.Debugf("End of wait ... [%p]", ctx)
|
||||
log.Debugf("End of wait ... [%p] key=[%s]", ctx, rec.key)
|
||||
}
|
||||
|
||||
rec.waiter.Pop(ctx)
|
||||
|
||||
if debug_log {
|
||||
log.Debugf("waiter size %d after pop", rec.waiter.Len())
|
||||
log.Debugf("waiter size %d after pop key=[%s]", rec.waiter.Len(), rec.key)
|
||||
}
|
||||
|
||||
rec.holder = ctx
|
||||
@@ -110,18 +115,18 @@ func (rec *SInMemoryLockRecord) unlockContext(ctx context.Context) (needClean bo
|
||||
defer rec.lock.Unlock()
|
||||
|
||||
if rec.holder != ctx {
|
||||
log.Fatalf("try to unlock a wait context???")
|
||||
rec.fatalf("try to unlock a wait context??? key=[%s]", rec.key)
|
||||
}
|
||||
|
||||
if debug_log {
|
||||
log.Debugf("unlockContext depth %d [%p]", rec.depth, ctx)
|
||||
log.Debugf("unlockContext depth %d [%p] key=[%s]", rec.depth, ctx, rec.key)
|
||||
}
|
||||
|
||||
rec.depth -= 1
|
||||
|
||||
if rec.depth <= 0 {
|
||||
if debug_log {
|
||||
log.Debugf("depth 0, to release lock for context [%p]", ctx)
|
||||
log.Debugf("depth 0, to release lock for context [%p] key=[%s]", ctx, rec.key)
|
||||
}
|
||||
|
||||
rec.holder = nil
|
||||
@@ -162,7 +167,9 @@ func (lockman *SInMemoryLockManager) getRecord(ctx context.Context, key string,
|
||||
if !new {
|
||||
return nil
|
||||
}
|
||||
lockman.lockTable[key] = newInMemoryLockRecord(ctx)
|
||||
rec := newInMemoryLockRecord(ctx)
|
||||
rec.key = key
|
||||
lockman.lockTable[key] = rec
|
||||
}
|
||||
return lockman.lockTable[key]
|
||||
}
|
||||
|
||||
@@ -245,9 +245,15 @@ func (manager *SMetadataManager) metaDataQuery2List(ctx context.Context, q *sqlc
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Query.All")
|
||||
}
|
||||
ciMap := map[string]string{}
|
||||
|
||||
ret := make([]jsonutils.JSONObject, len(metadatas))
|
||||
for i := range metadatas {
|
||||
if k, ok := ciMap[strings.ToLower(metadatas[i].Key)]; !ok {
|
||||
ciMap[strings.ToLower(metadatas[i].Key)] = metadatas[i].Key
|
||||
} else {
|
||||
metadatas[i].Key = k
|
||||
}
|
||||
if input.Details != nil && *input.Details {
|
||||
ret[i], err = manager.getKeyValueObjectCount(ctx, userCred, input, metadatas[i].Key, metadatas[i].Value, metadatas[i].Count)
|
||||
if err != nil {
|
||||
|
||||
@@ -385,7 +385,7 @@ func (self *SOpsLogManager) FilterByOwner(q *sqlchemy.SQuery, ownerId mcclient.I
|
||||
}
|
||||
case rbacutils.ScopeDomain:
|
||||
if len(ownerId.GetProjectDomainId()) > 0 {
|
||||
q = q.Filter(sqlchemy.Equals(q.Field("domain_id"), ownerId.GetProjectDomainId()))
|
||||
q = q.Filter(sqlchemy.Equals(q.Field("project_domain_id"), ownerId.GetProjectDomainId()))
|
||||
}
|
||||
default:
|
||||
// systemScope, no filter
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -37,8 +37,8 @@ func Error2TaskData(err error) jsonutils.JSONObject {
|
||||
return errJson
|
||||
}
|
||||
|
||||
func LocalTaskRun(task ITask, proc func() (jsonutils.JSONObject, error)) {
|
||||
localTaskWorkerMan.Run(func() {
|
||||
func LocalTaskRunWithWorkers(task ITask, proc func() (jsonutils.JSONObject, error), wm *appsrv.SWorkerManager) {
|
||||
wm.Run(func() {
|
||||
|
||||
log.Debugf("XXXXXXXXXXXXXXXXXXLOCAL TASK RUN STARTXXXXXXXXXXXXXXXXX")
|
||||
defer log.Debugf("XXXXXXXXXXXXXXXXXXLOCAL TASK RUN END XXXXXXXXXXXXXXXXX")
|
||||
@@ -59,3 +59,7 @@ func LocalTaskRun(task ITask, proc func() (jsonutils.JSONObject, error)) {
|
||||
|
||||
}, nil, nil)
|
||||
}
|
||||
|
||||
func LocalTaskRun(task ITask, proc func() (jsonutils.JSONObject, error)) {
|
||||
LocalTaskRunWithWorkers(task, proc, localTaskWorkerMan)
|
||||
}
|
||||
|
||||
@@ -82,12 +82,11 @@ func (manager *SInformerSyncManager) startWatcher() error {
|
||||
log.Infof("[%s] Start resource informer watcher for %s", manager.Name(), manager.resourceManager.GetKeyword())
|
||||
ctx := context.Background()
|
||||
s := auth.GetAdminSession(ctx, consts.GetRegion(), "v1")
|
||||
watchMan, err := informer.NewWatchManagerBySession(s)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "NewWatchManagerBySession")
|
||||
}
|
||||
if err := watchMan.For(manager.resourceManager).AddEventHandler(ctx, manager); err != nil {
|
||||
return errors.Wrapf(err, "watch resource %s", manager.resourceManager.GetKeyword())
|
||||
}
|
||||
informer.NewWatchManagerBySessionBg(s, func(watchMan *informer.SWatchManager) error {
|
||||
if err := watchMan.For(manager.resourceManager).AddEventHandler(ctx, manager); err != nil {
|
||||
return errors.Wrapf(err, "watch resource %s", manager.resourceManager.GetKeyword())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -93,7 +99,7 @@ type SNicDevInfo struct {
|
||||
Dev string `json:"dev"`
|
||||
Mac net.HardwareAddr `json:"mac"`
|
||||
Speed int `json:"speed"`
|
||||
Up bool `json:"up"`
|
||||
Up *bool `json:"up"`
|
||||
Mtu int `json:"mtu"`
|
||||
}
|
||||
|
||||
|
||||
35
pkg/cloudcommon/types/uefi.go
Normal file
35
pkg/cloudcommon/types/uefi.go
Normal 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
|
||||
}
|
||||
@@ -552,7 +552,7 @@ func (self *SCloudaccount) getCloudusers() ([]SClouduser, error) {
|
||||
|
||||
func (self *SCloudaccount) GetCloudusers() ([]SClouduser, error) {
|
||||
users := []SClouduser{}
|
||||
q := ClouduserManager.Query().Equals("status", api.CLOUD_USER_STATUS_AVAILABLE).Equals("cloudaccount_id", self.Id)
|
||||
q := ClouduserManager.Query().Equals("cloudaccount_id", self.Id)
|
||||
err := db.FetchModelObjects(ClouduserManager, q, &users)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "db.FetchModelObjects")
|
||||
@@ -564,7 +564,7 @@ func (self *SCloudaccount) SyncCloudusers(ctx context.Context, userCred mcclient
|
||||
result := compare.SyncResult{}
|
||||
dbUsers, err := self.GetCloudusers()
|
||||
if err != nil {
|
||||
result.Error(errors.Wrap(err, "GetCloudusersByProviderId"))
|
||||
result.Error(errors.Wrap(err, "GetCloudusers"))
|
||||
return nil, nil, result
|
||||
}
|
||||
|
||||
@@ -1130,6 +1130,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
|
||||
@@ -1193,7 +1194,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 {
|
||||
|
||||
@@ -85,6 +85,24 @@ var (
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Auth: true,
|
||||
Scope: rbacutils.ScopeUser,
|
||||
Rules: []rbacutils.SRbacRule{
|
||||
{
|
||||
Service: api.SERVICE_TYPE,
|
||||
Resource: "samlusers",
|
||||
Action: PolicyActionList,
|
||||
Result: rbacutils.Allow,
|
||||
},
|
||||
{
|
||||
Service: api.SERVICE_TYPE,
|
||||
Resource: "samlusers",
|
||||
Action: PolicyActionGet,
|
||||
Result: rbacutils.Allow,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ var (
|
||||
}
|
||||
cloudidUserResources = []string{
|
||||
"cloudusers",
|
||||
"samlusers",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -225,6 +225,8 @@ type ICloudProviderFactory interface {
|
||||
GetTTLRange(zoneType TDnsZoneType, productType TDnsProductType) TTlRange
|
||||
|
||||
IsSupportSAMLAuth() bool
|
||||
|
||||
GetAccountIdEqualizer() func(origin, now string) bool
|
||||
}
|
||||
|
||||
type ICloudProvider interface {
|
||||
@@ -711,6 +713,15 @@ func (factory *baseProviderFactory) GetTTLRange(zoneType TDnsZoneType, productTy
|
||||
return TTlRange{}
|
||||
}
|
||||
|
||||
func (factory *baseProviderFactory) GetAccountIdEqualizer() func(origin, now string) bool {
|
||||
return func(origin, now string) bool {
|
||||
if len(now) > 0 && now != origin {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
type SDnsCapability struct {
|
||||
ZoneTypes []TDnsZoneType
|
||||
DnsTypes map[TDnsZoneType][]TDnsType
|
||||
|
||||
@@ -16,7 +16,6 @@ package cloudprovider
|
||||
|
||||
type SSubAccount struct {
|
||||
Name string
|
||||
State string
|
||||
Account string
|
||||
HealthStatus string // 云端服务健康状态。例如欠费、项目冻结都属于不健康状态。
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,14 +197,6 @@ func (self *SAliyunGuestDriver) GetInstanceCapability() cloudprovider.SInstanceC
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SAliyunGuestDriver) GetLinuxDefaultAccount(desc cloudprovider.SManagedVMCreateConfig) string {
|
||||
userName := "root"
|
||||
if desc.OsType == "Windows" {
|
||||
userName = "Administrator"
|
||||
}
|
||||
return userName
|
||||
}
|
||||
|
||||
func (self *SAliyunGuestDriver) AllowReconfigGuest() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user