mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-30 17:13:08 +08:00
Merge branch 'release/2.6.0' of ssh://git.yunion.io/~qiujian/onecloud into feature/qj-image-p2p-distribution
Conflicts: pkg/appsrv/appsrv.go pkg/cloudcommon/policy/defaults.go pkg/util/sysutils/sysutils.go
This commit is contained in:
Generated
+60
-8
@@ -94,6 +94,14 @@
|
||||
revision = "879f631812a30a580659e8035e7cda9994bb99ac"
|
||||
version = "v1.20.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e92f5581902c345eb4ceffdcd4a854fb8f73cf436d47d837d1ec98ef1fe0a214"
|
||||
name = "github.com/StackExchange/wmi"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5d049714c4a64225c3c79a7cf7d02f7fb5b96338"
|
||||
version = "1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8c3176921eb3a8c3b9cadd2bbb2e8e39f62a99ee2e0965074a857868cc18a10b"
|
||||
name = "github.com/aliyun/alibaba-cloud-sdk-go"
|
||||
@@ -533,6 +541,17 @@
|
||||
revision = "07c9b44f60d7ffdfb7d8efe1ad539965737836dc"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c96d16a4451e48e2c44b2c3531fd8ec9248d822637f1911a88959ca0bcae4a64"
|
||||
name = "github.com/go-ole/go-ole"
|
||||
packages = [
|
||||
".",
|
||||
"oleutil",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "39dc8486bd0952279431257138bc428275b86797"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65"
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
@@ -1117,6 +1136,29 @@
|
||||
pruneopts = "UT"
|
||||
revision = "49a4782e9908fe098c907022a1bd7519c79803d6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:946db283b5540b64c60e7517b5afa54dc148b4672d69b38423a1c8d7fe24f3d1"
|
||||
name = "github.com/shirou/gopsutil"
|
||||
packages = [
|
||||
"cpu",
|
||||
"host",
|
||||
"internal/common",
|
||||
"mem",
|
||||
"net",
|
||||
"process",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "3ec50d2876a36047b2ca39f955ba88fb7a455e92"
|
||||
version = "v2.18.10"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:99c6a6dab47067c9b898e8c8b13d130c6ab4ffbcc4b7cc6236c2cd0b1e344f5b"
|
||||
name = "github.com/shirou/w32"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "bb4de0191aa41b5507caa14b0650cdbddcd9280b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:69b1cc331fca23d702bd72f860c6a647afd0aa9fcbc1d0659b1365e26546dd70"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
@@ -1615,11 +1657,11 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9e1972be6a76a8ef37aebcf94dedbe0508274464b5091baff4a8780583affebb"
|
||||
digest = "1:9a92b34083e218c123d21a4b0d74228df6b186de9dcd6489e5b4cf68f4e90104"
|
||||
name = "yunion.io/x/jsonutils"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c191216583f759c3d54a1d1d84c9832fdee68596"
|
||||
revision = "c40afc81cccc4618168f722c64deba7cfbb1f8bd"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -1634,7 +1676,7 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c6edf85623ec3a8c5e688dafbdc5bbde1d6057b9d0d9b78e6cb6dd84a52b23c0"
|
||||
digest = "1:6277045f9c9a63d84e1aa48c7ad3c1f42ea6523bc54ea92e772d541c78e37404"
|
||||
name = "yunion.io/x/pkg"
|
||||
packages = [
|
||||
"gotypes",
|
||||
@@ -1657,6 +1699,7 @@
|
||||
"util/seclib",
|
||||
"util/secrules",
|
||||
"util/sets",
|
||||
"util/signalutils",
|
||||
"util/stringutils",
|
||||
"util/timeutils",
|
||||
"util/trace",
|
||||
@@ -1667,23 +1710,23 @@
|
||||
"utils",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "9075712a1c3ff8c0bad1c413e18f0b7f2c18f29c"
|
||||
revision = "e2e42205d868c26829b9322b40cdc48f24fed379"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:82629c6aeecc1e6e3ea7108385aaac2bdcceeba8f8dc3175daca256602e3be71"
|
||||
digest = "1:0e3c8da76b7b7ba0f67ef0737d361e117b65bd328bfbcb28fb030268df587ca9"
|
||||
name = "yunion.io/x/sqlchemy"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2445071ddf7b3f2a22ccdd3be684b67ac2f9008"
|
||||
revision = "0b1ca973f3e5140dee7e773fc51cfc8c07ce0f69"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:6ea9ac8f317e7dd79309bb1633642bc9d1822011c5175bd241552534d216ac6d"
|
||||
digest = "1:cec4892868ae1c9fec0d2cace79d4c43e620345cc3c070d004dec09caf197208"
|
||||
name = "yunion.io/x/structarg"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e4f0f5201b4acad185ebfb76e65905fe5ae7c1b1"
|
||||
revision = "f39549642b91f03f0b46403f9856d4750e3e59eb"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
@@ -1759,6 +1802,11 @@
|
||||
"github.com/nelsonken/cos-go-sdk-v5/cos",
|
||||
"github.com/pierrec/lz4",
|
||||
"github.com/serialx/hashring",
|
||||
"github.com/shirou/gopsutil/cpu",
|
||||
"github.com/shirou/gopsutil/host",
|
||||
"github.com/shirou/gopsutil/mem",
|
||||
"github.com/shirou/gopsutil/net",
|
||||
"github.com/shirou/gopsutil/process",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common",
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http",
|
||||
@@ -1774,6 +1822,9 @@
|
||||
"github.com/vmware/govmomi/vim25/types",
|
||||
"go.etcd.io/etcd/clientv3",
|
||||
"golang.org/x/crypto/ssh",
|
||||
"golang.org/x/net/bpf",
|
||||
"golang.org/x/net/ipv4",
|
||||
"golang.org/x/sys/unix",
|
||||
"gopkg.in/gin-gonic/gin.v1",
|
||||
"k8s.io/api/core/v1",
|
||||
"k8s.io/apimachinery/pkg/api/errors",
|
||||
@@ -1804,6 +1855,7 @@
|
||||
"yunion.io/x/pkg/util/seclib",
|
||||
"yunion.io/x/pkg/util/secrules",
|
||||
"yunion.io/x/pkg/util/sets",
|
||||
"yunion.io/x/pkg/util/signalutils",
|
||||
"yunion.io/x/pkg/util/stringutils",
|
||||
"yunion.io/x/pkg/util/timeutils",
|
||||
"yunion.io/x/pkg/util/trace",
|
||||
|
||||
@@ -195,3 +195,7 @@
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/shirou/gopsutil"
|
||||
version = "2.18.10"
|
||||
|
||||
+3
-1
@@ -128,7 +128,9 @@ getent passwd %{owner} >/dev/null || /usr/sbin/useradd -r -s /sbin/nologin -d %{
|
||||
$(for b in $EXTRA_BINS; do echo /opt/yunion/bin/$b; done)
|
||||
" > $SPEC_FILE
|
||||
|
||||
find $ROOT/root/ -type f | sed -e "s:$ROOT/root::g" >> $SPEC_FILE
|
||||
if [ -d $ROOT/root/ ]; then
|
||||
find $ROOT/root/ -type f | sed -e "s:$ROOT/root::g" >> $SPEC_FILE
|
||||
fi
|
||||
|
||||
rpmbuild --define "_topdir $BUILDROOT" -bb $SPEC_FILE
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
region = 'LocalTest'
|
||||
port = 9999
|
||||
auth_uri = 'http://10.16.22.51:35357/v2.0'
|
||||
admin_user = 'logadmin'
|
||||
admin_password = 'password0'
|
||||
admin_tenant_name = 'system'
|
||||
sql_connection = 'mysql+pymysql://yunionlogger:password0@10.16.22.51:3306/yunionlogger?charset=utf8'
|
||||
|
||||
auto_sync_table = True
|
||||
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Yunion Cloud Log Service
|
||||
Documentation=http://doc.yunionyun.com
|
||||
After=network.target httpd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=yunion
|
||||
Group=yunion
|
||||
ExecStart=/opt/yunion/bin/logger --config /etc/yunion/log.conf
|
||||
WorkingDirectory=/opt/yunion
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1 @@
|
||||
DESCRIPTION="Yunion Cloud Log Service"
|
||||
+1
@@ -0,0 +1 @@
|
||||
您的云主机{{ .name }}的套餐类型已经更改为 CPU:{{ index .flavor_info "cpu" }}核,内存:{{ index .flavor_info "memory" }}M,数据盘:{{ index .flavor_info "datadisk" }}G,带宽: {{ index .flavor_info "ebw" }}M。
|
||||
@@ -0,0 +1 @@
|
||||
您的云主机{{ .name }}已经创建成功,服务器IP地址为{{ .ips }},{{ if .account }}初始帐号为{{ .account }},{{ end }}{{ if .keypair }}访问ssh密钥为{{ .keypair }},{{ end }}{{ if .password }}初始密码为{{ .password }},{{ end }}请使用{{ if .windows }}远程桌面连接器(RDC){{ else }}SSH{{ end }}或控制面板控制台访问云主机。
|
||||
+1
@@ -0,0 +1 @@
|
||||
用户{{ .tenant }}的云主机{{ .name }}已经创建成功。
|
||||
@@ -0,0 +1 @@
|
||||
您的云主机{{ .name }}已经删除。
|
||||
+1
@@ -0,0 +1 @@
|
||||
用户{{ .tenant }}的云主机{{ .name }}已经删除。
|
||||
+1
@@ -0,0 +1 @@
|
||||
您的云主机{{ .name }}的系统盘已经重置成功,{{ if .account }}初始帐号为{{ .account }},{{ end }}{{ if .keypair }}访问密钥为{{ .keypair }},{{ end }}{{ if .password }}初始密码为{{ .password }},{{ end }}请使用{{ if .windows }}远程桌面连接器(RDC){{ else }}SSH{{ end }}或控制面板控制台访问云主机。
|
||||
@@ -0,0 +1 @@
|
||||
系统错误消息:{{ .msg }}({{ .created }})
|
||||
@@ -0,0 +1 @@
|
||||
系统警告消息:{{ .msg }}({{ .created }})
|
||||
@@ -0,0 +1 @@
|
||||
您的云主机{{ .name }}的套餐类型已经更改为 CPU:{{ index .flavor_info "cpu" }}核,内存:{{ index .flavor_info "memory" }}M,数据盘:{{ index .flavor_info "datadisk" }}G,带宽: {{ index .flavor_info "ebw" }}M。
|
||||
@@ -0,0 +1 @@
|
||||
云主机{{ .Name }}创建成功
|
||||
@@ -0,0 +1 @@
|
||||
用户{{ .tenant }}的云主机{{ .name }}已经创建成功
|
||||
@@ -0,0 +1 @@
|
||||
云主机{{ .name }}删除通知
|
||||
@@ -0,0 +1 @@
|
||||
用户{{ .tenant }}的云主机{{ .name }}已经删除
|
||||
@@ -0,0 +1 @@
|
||||
云主机{{ .name }}的系统盘重置成功
|
||||
@@ -0,0 +1 @@
|
||||
系统错误消息:{{ .msg }}({{ .created }})
|
||||
@@ -0,0 +1 @@
|
||||
系统警告消息:{{ .msg }}({{ .created }})
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
)
|
||||
|
||||
type BaseOptions struct {
|
||||
Debug bool `help:"debug mode"`
|
||||
Help bool `help:"Show help"`
|
||||
AccessKey string `help:"Access key" default:"$ALIYUN_ACCESS_KEY"`
|
||||
Secret string `help:"Secret" default:"$ALIYUN_SECRET"`
|
||||
@@ -69,7 +70,7 @@ func newClient(options *BaseOptions) (*aliyun.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cli, err := aliyun.NewAliyunClient("", "", options.AccessKey, options.Secret)
|
||||
cli, err := aliyun.NewAliyunClient("", "", options.AccessKey, options.Secret, options.Debug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/baremetal/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
service.New().StartService()
|
||||
}
|
||||
@@ -16,6 +16,7 @@ type BaseActionListOptions struct {
|
||||
Descending bool `help:"Descending order"`
|
||||
Action []string `help:"Log action"`
|
||||
Search string `help:"Filter action logs by obj_name, using 'like' syntax."`
|
||||
Admin bool `help:"admin mode"`
|
||||
}
|
||||
|
||||
type ActionListOptions struct {
|
||||
@@ -60,6 +61,9 @@ func doActionList(s *mcclient.ClientSession, args *ActionListOptions) error {
|
||||
if len(args.Action) > 0 {
|
||||
params.Add(jsonutils.NewStringArray(args.Action), "action")
|
||||
}
|
||||
if args.Admin {
|
||||
params.Add(jsonutils.JSONTrue, "admin")
|
||||
}
|
||||
logs, err := modules.Actions.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -346,7 +346,7 @@ func init() {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewInt(args.ENABLED), "enabled")
|
||||
|
||||
_, err := modules.AlarmTemplateAlarms.Update(s, args.ALARMTEMPLATE_ID, args.ALARM_ID, params)
|
||||
_, err := modules.AlarmTemplateAlarms.Update(s, args.ALARMTEMPLATE_ID, args.ALARM_ID, nil, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
@@ -10,16 +9,15 @@ import (
|
||||
func init() {
|
||||
type CachedImageListOptions struct {
|
||||
options.BaseListOptions
|
||||
ImageType string `help:"image type" choices:"system|customized|shared|market"`
|
||||
|
||||
Region string `help:"show images cached at cloud region"`
|
||||
Zone string `help:"show images cached at zone"`
|
||||
}
|
||||
R(&CachedImageListOptions{}, "cached-image-list", "List cached images", func(s *mcclient.ClientSession, args *CachedImageListOptions) error {
|
||||
var params *jsonutils.JSONDict
|
||||
{
|
||||
var err error
|
||||
params, err = args.BaseListOptions.Params()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
params, err := options.ListStructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Cachedimages.List(s, params)
|
||||
if err != nil {
|
||||
@@ -50,12 +48,12 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&CachedImageShowOptions{}, "cached-image-delete", "Remove cached image information", func(s *mcclient.ClientSession, args *CachedImageShowOptions) error {
|
||||
result, err := modules.Cachedimages.Delete(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
type CachedImageDeleteOptions struct {
|
||||
ID []string `help:"ID or Name of the cached image to show"`
|
||||
}
|
||||
R(&CachedImageDeleteOptions{}, "cached-image-delete", "Remove cached image information", func(s *mcclient.ClientSession, args *CachedImageDeleteOptions) error {
|
||||
results := modules.Cachedimages.BatchDelete(s, args.ID, nil)
|
||||
printBatchResults(results, modules.Cachedimages.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -31,13 +33,25 @@ func init() {
|
||||
})
|
||||
|
||||
type CloudaccountCreateOptions struct {
|
||||
NAME string `help:"Name of cloud account"`
|
||||
ACCOUNT string `help:"Account to access the cloud account"`
|
||||
SECRET string `help:"Secret to access the cloud account, clientId/clientScret for Azure"`
|
||||
PROVIDER string `help:"Driver for cloud account" choices:"VMware|Aliyun|Azure|Qcloud|OpenStack|Huawei"`
|
||||
AccessURL string `helo:"hello" metavar:"Azure choices: <AzureGermanCloud、AzureChinaCloud、AzureUSGovernmentCloud、AzurePublicCloud>"`
|
||||
Desc string `help:"Description"`
|
||||
Enabled bool `help:"Enabled the account automatically"`
|
||||
NAME string `help:"Name of cloud account"`
|
||||
AccessKeyID string `help:"Aiyun|HuaWei|Aws access_key_id"`
|
||||
AccessKeySecret string `help:"Aiyun|HuaWei|Aws access_key_secret"`
|
||||
AppID string `help:"Qcloud appid"`
|
||||
SecretID string `help:"Qcloud secret_id"`
|
||||
SecretKey string `help:"Qcloud secret_key"`
|
||||
ProjectName string `help:"OpenStack project_name"`
|
||||
Username string `help:"OpenStack|VMware username"`
|
||||
Password string `help:"OpenStack|VMware password"`
|
||||
AuthURL string `help:"OpenStack auth_url"`
|
||||
Host string `help:"VMware host"`
|
||||
Port string `help:"VMware host port" default:"443"`
|
||||
DirectoryID string `help:"Azure directory_id"`
|
||||
ClientID string `help:"Azure client_id"`
|
||||
ClientSecret string `help:"Azure clinet_secret"`
|
||||
Environment string `help:"Azure|Huawei|Aws environment" choices:"AzureGermanCloud|AzureChinaCloud|AzureUSGovernmentCloud|AzurePublicCloud|InternationalCloud|ChinaCloud|"`
|
||||
PROVIDER string `help:"Driver for cloud account" choices:"VMware|Aliyun|Azure|Qcloud|OpenStack|Huawei|Aws"`
|
||||
Desc string `help:"Description"`
|
||||
Enabled bool `help:"Enabled the account automatically"`
|
||||
|
||||
Import bool `help:"Import all sub account automatically"`
|
||||
AutoSync bool `help:"Enabled the account automatically"`
|
||||
@@ -46,9 +60,31 @@ func init() {
|
||||
R(&CloudaccountCreateOptions{}, "cloud-account-create", "Create a cloud account", func(s *mcclient.ClientSession, args *CloudaccountCreateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.NAME), "name")
|
||||
params.Add(jsonutils.NewString(args.ACCOUNT), "account")
|
||||
params.Add(jsonutils.NewString(args.SECRET), "secret")
|
||||
params.Add(jsonutils.NewString(args.PROVIDER), "provider")
|
||||
data := jsonutils.Marshal(args)
|
||||
|
||||
requireParamsMap := map[string][]string{
|
||||
"VMware": {"username", "password", "host", "port"},
|
||||
"Aliyun": {"access_key_id", "access_key_secret"},
|
||||
"Azure": {"directory_id", "client_id", "client_secret", "environment"},
|
||||
"Qcloud": {"app_id", "secret_id", "secret_key"},
|
||||
"OpenStack": {"project_name", "username", "password", "auth_url"},
|
||||
"Huawei": {"access_key_id", "access_key_secret", "environment"},
|
||||
"Aws": {"access_key_id", "access_key_secret", "environment"},
|
||||
}
|
||||
|
||||
requireParams, ok := requireParamsMap[args.PROVIDER]
|
||||
if !ok {
|
||||
return fmt.Errorf("Unsupport provider %s", args.PROVIDER)
|
||||
}
|
||||
|
||||
for _, key := range requireParams {
|
||||
v, _ := data.GetString(key)
|
||||
if len(v) == 0 {
|
||||
return fmt.Errorf("Missing %s", key)
|
||||
}
|
||||
params.Add(jsonutils.NewString(v), key)
|
||||
}
|
||||
|
||||
if args.Enabled {
|
||||
params.Add(jsonutils.JSONTrue, "enabled")
|
||||
@@ -64,9 +100,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
if len(args.AccessURL) > 0 {
|
||||
params.Add(jsonutils.NewString(args.AccessURL), "access_url")
|
||||
}
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
}
|
||||
@@ -182,15 +215,20 @@ func init() {
|
||||
})
|
||||
|
||||
type CloudaccountUpdateCredentialOptions struct {
|
||||
ID string `help:"ID or Name of cloud account"`
|
||||
ACCOUNT string `help:"new account"`
|
||||
SECRET string `help:"new secret"`
|
||||
ID string `help:"ID or Name of cloud account"`
|
||||
AccessKeyID string `help:"Aiyun|HuaWei|Aws access_key_id"`
|
||||
AccessKeySecret string `help:"Aiyun|HuaWei|Aws access_key_secret"`
|
||||
AppID string `help:"Qcloud appid"`
|
||||
SecretID string `help:"Qcloud secret_id"`
|
||||
SecretKey string `help:"Qcloud secret_key"`
|
||||
ProjectName string `help:"OpenStack project_name"`
|
||||
Username string `help:"OpenStack|VMware username"`
|
||||
Password string `help:"OpenStack|VMware password"`
|
||||
ClientID string `help:"Azure tenant_id"`
|
||||
ClientSecret string `help:"Azure clinet_secret"`
|
||||
}
|
||||
R(&CloudaccountUpdateCredentialOptions{}, "cloud-account-update-credential", "Update credential of a cloud account", func(s *mcclient.ClientSession, args *CloudaccountUpdateCredentialOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.ACCOUNT), "account")
|
||||
params.Add(jsonutils.NewString(args.SECRET), "secret")
|
||||
|
||||
params := jsonutils.Marshal(args)
|
||||
result, err := modules.Cloudaccounts.PerformAction(s, args.ID, "update-credential", params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -15,6 +15,8 @@ func init() {
|
||||
Public *bool `help:"show public cloud regions only" json:"is_public"`
|
||||
Usable *bool `help:"List regions where networks are usable"`
|
||||
UsableVpc *bool `help:"List regions where VPC are usable"`
|
||||
|
||||
City string `help:"List regions in the specified city"`
|
||||
}
|
||||
R(&CloudregionListOptions{}, "cloud-region-list", "List cloud regions", func(s *mcclient.ClientSession, opts *CloudregionListOptions) error {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
@@ -29,20 +31,66 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type CloudregionCityListOptions struct {
|
||||
Manager string `help:"List objects belonging to the cloud provider"`
|
||||
Account string `help:"List objects belonging to the cloud account"`
|
||||
Provider string `help:"List objects from the provider" choices:"VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack"`
|
||||
|
||||
Private *bool `help:"show private cloud regions only" json:"is_private"`
|
||||
Public *bool `help:"show public cloud regions only" json:"is_public"`
|
||||
Usable *bool `help:"List regions where networks are usable"`
|
||||
UsableVpc *bool `help:"List regions where VPC are usable"`
|
||||
}
|
||||
R(&CloudregionCityListOptions{}, "cloud-region-cities", "List cities where cloud region resides", func(s *mcclient.ClientSession, args *CloudregionCityListOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results, err := modules.Cloudregions.GetRegionCities(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listResult := modules.ListResult{}
|
||||
listResult.Data, err = results.GetArray()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(&listResult, nil)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&CloudregionCityListOptions{}, "cloud-region-providers", "List cities where cloud region resides", func(s *mcclient.ClientSession, args *CloudregionCityListOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results, err := modules.Cloudregions.GetRegionProviders(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listResult := modules.ListResult{}
|
||||
listResult.Data, err = results.GetArray()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(&listResult, nil)
|
||||
return nil
|
||||
})
|
||||
|
||||
type CloudregionCreateOptions struct {
|
||||
Id string `help:"ID of the region"`
|
||||
NAME string `help:"Name of the region"`
|
||||
Provider string `help:"Cloud provider"`
|
||||
Desc string `help:"Description"`
|
||||
Id string `help:"ID of the region"`
|
||||
NAME string `help:"Name of the region"`
|
||||
Provider string `help:"Cloud provider"`
|
||||
Desc string `help:"Description" json:"description" token:"desc"`
|
||||
Latitude float32 `help:"region geographical location - latitude"`
|
||||
Longitude float32 `help:"region geographical location - longitude"`
|
||||
City string `help:"region geograpical location - city, e.g. Beijing, Frankfurt"`
|
||||
CountryCode string `help:"region geographical location - ISO country code, e.g. CN"`
|
||||
}
|
||||
R(&CloudregionCreateOptions{}, "cloud-region-create", "Create a cloud region", func(s *mcclient.ClientSession, args *CloudregionCreateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.NAME), "name")
|
||||
if len(args.Id) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Id), "id")
|
||||
}
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results, err := modules.Cloudregions.Create(s, params)
|
||||
if err != nil {
|
||||
@@ -74,17 +122,18 @@ func init() {
|
||||
})
|
||||
|
||||
type CloudregionUpdateOptions struct {
|
||||
ID string `help:"ID or name of the region"`
|
||||
Name string `help:"New name of the region"`
|
||||
Desc string `help:"Description of the region"`
|
||||
ID string `help:"ID or name of the region to update" json:"-"`
|
||||
Name string `help:"New name of the region"`
|
||||
Desc string `help:"Description of the region" json:"description" token:"desc"`
|
||||
Latitude float32 `help:"region geographical location - latitude"`
|
||||
Longitude float32 `help:"region geographical location - longitude"`
|
||||
City string `help:"region geograpical location - city, e.g. Beijing, Frankfurt"`
|
||||
CountryCode string `help:"region geographical location - ISO country code, e.g. CN"`
|
||||
}
|
||||
R(&CloudregionUpdateOptions{}, "cloud-region-update", "Update a cloud region", func(s *mcclient.ClientSession, args *CloudregionUpdateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
if len(args.Name) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Name), "name")
|
||||
}
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results, err := modules.Cloudregions.Update(s, args.ID, params)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,13 +11,13 @@ import (
|
||||
func init() {
|
||||
type DiskListOptions struct {
|
||||
options.BaseListOptions
|
||||
|
||||
Unused *bool `help:"Show unused disks"`
|
||||
Share *bool `help:"Show Share storage disks"`
|
||||
Local *bool `help:"Show Local storage disks"`
|
||||
Guest string `help:"Guest ID or name"`
|
||||
Storage string `help:"Storage ID or name"`
|
||||
Type string `help:"Disk type" choices:"sys|data|swap|volume"`
|
||||
Unused *bool `help:"Show unused disks"`
|
||||
Share *bool `help:"Show Share storage disks"`
|
||||
Local *bool `help:"Show Local storage disks"`
|
||||
Guest string `help:"Guest ID or name"`
|
||||
Storage string `help:"Storage ID or name"`
|
||||
Type string `help:"Disk type" choices:"sys|data|swap|volume"`
|
||||
CloudType string `help:"Public cloud or private cloud" choices:"Public|Private"`
|
||||
|
||||
BillingType string `help:"billing type" choices:"postpaid|prepaid"`
|
||||
}
|
||||
@@ -26,6 +26,14 @@ func init() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(opts.CloudType) > 0 {
|
||||
if opts.CloudType == "Public" {
|
||||
params.Add(jsonutils.JSONTrue, "public_cloud")
|
||||
} else if opts.CloudType == "Private" {
|
||||
params.Add(jsonutils.JSONTrue, "private_cloud")
|
||||
}
|
||||
}
|
||||
|
||||
result, err := modules.Disks.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -230,4 +238,41 @@ func init() {
|
||||
printObject(disk)
|
||||
return nil
|
||||
})
|
||||
|
||||
type DiskSaveOptions struct {
|
||||
ID string `help:"ID or name of the disk" json:"-"`
|
||||
NAME string `help:"Image name"`
|
||||
OSTYPE string `help:"Os type" choices:"Linux|Windows|VMware" json:"-"`
|
||||
Public *bool `help:"Make the image public available" json:"is_public"`
|
||||
Format string `help:"image format" choices:"vmdk|qcow2"`
|
||||
Notes string `help:"Notes about the image"`
|
||||
}
|
||||
R(&DiskSaveOptions{}, "disk-save", "Disk save image", func(s *mcclient.ClientSession, args *DiskSaveOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Add(jsonutils.NewString(args.OSTYPE), "properties", "os_type")
|
||||
disk, err := modules.Disks.PerformAction(s, args.ID, "save", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(disk)
|
||||
return nil
|
||||
})
|
||||
|
||||
type DiskUpdateStatusOptions struct {
|
||||
ID string `help:"ID or name of disk"`
|
||||
STATUS string `help:"Disk status" choices:"ready"`
|
||||
}
|
||||
R(&DiskUpdateStatusOptions{}, "disk-update-status", "Set disk status", func(s *mcclient.ClientSession, args *DiskUpdateStatusOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.STATUS), "status")
|
||||
disk, err := modules.Disks.PerformAction(s, args.ID, "status", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(disk)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -71,6 +71,9 @@ func init() {
|
||||
ID string `help:"ID or name of EIP"`
|
||||
Name string `help:"New name of EIP"`
|
||||
Desc string `help:"New description of EIP"`
|
||||
|
||||
EnableAutoDellocate bool `help:"enable automatically dellocate when dissociate from instance"`
|
||||
DisableAutoDellocate bool `help:"disable automatically dellocate when dissociate from instance"`
|
||||
}
|
||||
R(&EipUpdateOptions{}, "eip-update", "Update EIP properties", func(s *mcclient.ClientSession, args *EipUpdateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
@@ -80,6 +83,11 @@ func init() {
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
}
|
||||
if args.EnableAutoDellocate {
|
||||
params.Add(jsonutils.JSONTrue, "auto_dellocate")
|
||||
} else if args.DisableAutoDellocate {
|
||||
params.Add(jsonutils.JSONFalse, "auto_dellocate")
|
||||
}
|
||||
result, err := modules.Elasticips.Update(s, args.ID, params)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -105,11 +113,16 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type EipSingleOptions struct {
|
||||
ID string `help:"ID or name of EIP"`
|
||||
type EipDissociateOptions struct {
|
||||
ID string `help:"ID or name of EIP"`
|
||||
AutoDelete bool `help:"automatically delete the dissociate EIP" json:"auto_delete,omitfalse"`
|
||||
}
|
||||
R(&EipSingleOptions{}, "eip-dissociate", "Dissociate an EIP from an instance", func(s *mcclient.ClientSession, args *EipSingleOptions) error {
|
||||
result, err := modules.Elasticips.PerformAction(s, args.ID, "dissociate", nil)
|
||||
R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP from an instance", func(s *mcclient.ClientSession, args *EipDissociateOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Elasticips.PerformAction(s, args.ID, "dissociate", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -117,6 +130,9 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type EipSingleOptions struct {
|
||||
ID string `help:"ID or name of EIP"`
|
||||
}
|
||||
R(&EipSingleOptions{}, "eip-sync", "Synchronize status of an EIP", func(s *mcclient.ClientSession, args *EipSingleOptions) error {
|
||||
result, err := modules.Elasticips.PerformAction(s, args.ID, "sync", nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -50,7 +50,7 @@ func init() {
|
||||
if params.Size() == 0 {
|
||||
return InvalidUpdateError()
|
||||
}
|
||||
result, err := modules.Hostcachedimages.Update(s, args.HOST, args.IMAGE, params)
|
||||
result, err := modules.Hostcachedimages.Update(s, args.HOST, args.IMAGE, nil, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func init() {
|
||||
})
|
||||
|
||||
R(&HostStorageDetailOptions{}, "host-storage-detach", "Detach a storage from a host", func(s *mcclient.ClientSession, args *HostStorageDetailOptions) error {
|
||||
result, err := modules.Hoststorages.Detach(s, args.HOST, args.STORAGE)
|
||||
result, err := modules.Hoststorages.Detach(s, args.HOST, args.STORAGE, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func init() {
|
||||
params.Add(jsonutils.JSONFalse, "is_master")
|
||||
}
|
||||
}
|
||||
result, err := modules.Hostwires.Update(s, args.HOST, args.WIRE, params)
|
||||
result, err := modules.Hostwires.Update(s, args.HOST, args.WIRE, nil, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -91,7 +91,7 @@ func init() {
|
||||
WIRE string `help:"ID or Name of Wire"`
|
||||
}
|
||||
R(&HostWireDetachOptions{}, "host-wire-detach", "Detach host from wire", func(s *mcclient.ClientSession, args *HostWireDetachOptions) error {
|
||||
result, err := modules.Hostwires.Detach(s, args.HOST, args.WIRE)
|
||||
result, err := modules.Hostwires.Detach(s, args.HOST, args.WIRE, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -251,16 +251,17 @@ func init() {
|
||||
ID string `help:"Image ID or name"`
|
||||
}
|
||||
|
||||
R(&ImageDetailOptions{}, "image-delete", "Delete a image", func(s *mcclient.ClientSession, args *ImageDetailOptions) error {
|
||||
imgID, err := modules.Images.GetId(s, args.ID, nil)
|
||||
type ImageDeleteOptions struct {
|
||||
ID []string `help:"Image ID or name"`
|
||||
OverridePendingDelete *bool `help:"Delete image directly instead of pending delete"`
|
||||
}
|
||||
R(&ImageDeleteOptions{}, "image-delete", "Delete a image", func(s *mcclient.ClientSession, args *ImageDeleteOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result, err := modules.Images.Delete(s, imgID, nil); err != nil {
|
||||
return err
|
||||
} else {
|
||||
printObject(result)
|
||||
}
|
||||
ret := modules.Images.BatchDeleteWithParam(s, args.ID, params, nil)
|
||||
printBatchResults(ret, modules.Images.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
@@ -93,6 +93,14 @@ func init() {
|
||||
printLbAcl(lbacl)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerAclDeleteOptions{}, "lbacl-purge", "Purge lbacl", func(s *mcclient.ClientSession, opts *options.LoadbalancerAclDeleteOptions) error {
|
||||
lbacl, err := modules.LoadbalancerAcls.PerformAction(s, opts.ID, "purge", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printLbAcl(lbacl)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerAclDeleteOptions{}, "lbacl-delete", "Show lbacl", func(s *mcclient.ClientSession, opts *options.LoadbalancerAclDeleteOptions) error {
|
||||
lbacl, err := modules.LoadbalancerAcls.Delete(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
func init() {
|
||||
R(&options.LoadbalancerBackendGroupCreateOptions{}, "lbbackendgroup-create", "Create lbbackendgroup", func(s *mcclient.ClientSession, opts *options.LoadbalancerBackendGroupCreateOptions) error {
|
||||
params, err := options.StructToParams(opts)
|
||||
params, err := opts.Params()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func init() {
|
||||
printObject(lbbackendgroup)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerBackendGroupDeleteOptions{}, "lbbackendgroup-delete", "Show lbbackendgroup", func(s *mcclient.ClientSession, opts *options.LoadbalancerBackendGroupDeleteOptions) error {
|
||||
R(&options.LoadbalancerBackendGroupDeleteOptions{}, "lbbackendgroup-delete", "Delete lbbackendgroup", func(s *mcclient.ClientSession, opts *options.LoadbalancerBackendGroupDeleteOptions) error {
|
||||
lbbackendgroup, err := modules.LoadbalancerBackendGroups.Delete(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -59,4 +59,12 @@ func init() {
|
||||
printObject(lbbackendgroup)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerBackendGroupDeleteOptions{}, "lbbackendgroup-purge", "Purge lbbackendgroup", func(s *mcclient.ClientSession, opts *options.LoadbalancerBackendGroupDeleteOptions) error {
|
||||
lbbackendgroup, err := modules.LoadbalancerBackendGroups.PerformAction(s, opts.ID, "purge", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lbbackendgroup)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func init() {
|
||||
printObject(lbbackend)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerBackendDeleteOptions{}, "lbbackend-delete", "Show lbbackend", func(s *mcclient.ClientSession, opts *options.LoadbalancerBackendDeleteOptions) error {
|
||||
R(&options.LoadbalancerBackendDeleteOptions{}, "lbbackend-delete", "Delete lbbackend", func(s *mcclient.ClientSession, opts *options.LoadbalancerBackendDeleteOptions) error {
|
||||
lbbackend, err := modules.LoadbalancerBackends.Delete(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -56,4 +56,12 @@ func init() {
|
||||
printObject(lbbackend)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerBackendDeleteOptions{}, "lbbackend-purge", "Purge lbbackend", func(s *mcclient.ClientSession, opts *options.LoadbalancerBackendDeleteOptions) error {
|
||||
lbbackend, err := modules.LoadbalancerBackends.PerformAction(s, opts.ID, "purge", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lbbackend)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func init() {
|
||||
printObject(lbcert)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerCertificateDeleteOptions{}, "lbcert-delete", "Show lbcert", func(s *mcclient.ClientSession, opts *options.LoadbalancerCertificateDeleteOptions) error {
|
||||
R(&options.LoadbalancerCertificateDeleteOptions{}, "lbcert-delete", "Delete lbcert", func(s *mcclient.ClientSession, opts *options.LoadbalancerCertificateDeleteOptions) error {
|
||||
lbcert, err := modules.LoadbalancerCertificates.Delete(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -59,4 +59,12 @@ func init() {
|
||||
printObject(lbcert)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerCertificateDeleteOptions{}, "lbcert-purge", "Purge lbcert", func(s *mcclient.ClientSession, opts *options.LoadbalancerCertificateDeleteOptions) error {
|
||||
lbcert, err := modules.LoadbalancerCertificates.PerformAction(s, opts.ID, "purge", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lbcert)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func init() {
|
||||
printObject(lblistenerrule)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerListenerRuleDeleteOptions{}, "lblistenerrule-delete", "Show lblistenerrule", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerRuleDeleteOptions) error {
|
||||
R(&options.LoadbalancerListenerRuleDeleteOptions{}, "lblistenerrule-delete", "Delete lblistenerrule", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerRuleDeleteOptions) error {
|
||||
lblistenerrule, err := modules.LoadbalancerListenerRules.Delete(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -54,6 +54,14 @@ func init() {
|
||||
printObject(lblistenerrule)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerListenerRuleDeleteOptions{}, "lblistenerrule-purge", "Purge lblistenerrule", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerRuleDeleteOptions) error {
|
||||
lblistenerrule, err := modules.LoadbalancerListenerRules.PerformAction(s, opts.ID, "purge", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lblistenerrule)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerListenerRuleActionStatusOptions{}, "lblistenerrule-status", "Change lblistenerrule status", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerRuleActionStatusOptions) error {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
|
||||
@@ -48,7 +48,7 @@ func init() {
|
||||
printObject(lblistener)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerListenerDeleteOptions{}, "lblistener-delete", "Show lblistener", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerDeleteOptions) error {
|
||||
R(&options.LoadbalancerListenerDeleteOptions{}, "lblistener-delete", "Delete lblistener", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerDeleteOptions) error {
|
||||
lblistener, err := modules.LoadbalancerListeners.Delete(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -56,6 +56,14 @@ func init() {
|
||||
printObject(lblistener)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerListenerDeleteOptions{}, "lblistener-purge", "Purge lblistener", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerDeleteOptions) error {
|
||||
lblistener, err := modules.LoadbalancerListeners.PerformAction(s, opts.ID, "purge", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lblistener)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerListenerActionStatusOptions{}, "lblistener-status", "Change lblistener status", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerActionStatusOptions) error {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
@@ -68,4 +76,12 @@ func init() {
|
||||
printObject(lblistener)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerListenerActionSyncStatusOptions{}, "lblistener-syncstatus", "Sync lblistener status", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerActionSyncStatusOptions) error {
|
||||
lblistener, err := modules.LoadbalancerListeners.PerformAction(s, opts.ID, "syncstatus", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lblistener)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type LoadbalancerNetworkListOptions struct {
|
||||
options.BaseListOptions
|
||||
Loadbalancer string `help:"ID or Name of Loadbalancer"`
|
||||
Network string `help:"ID or Name of network"`
|
||||
Ip string `help:"search the IP address"`
|
||||
}
|
||||
R(&LoadbalancerNetworkListOptions{}, "loadbalancer-network-list", "List loadbalancer network pairs", func(s *mcclient.ClientSession, args *LoadbalancerNetworkListOptions) error {
|
||||
var params *jsonutils.JSONDict
|
||||
{
|
||||
var err error
|
||||
params, err = args.BaseListOptions.Params()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
if len(args.Ip) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Ip), "ip_addr")
|
||||
}
|
||||
var result *modules.ListResult
|
||||
var err error
|
||||
if len(args.Loadbalancer) > 0 {
|
||||
result, err = modules.Loadbalancernetworks.ListDescendent(s, args.Loadbalancer, params)
|
||||
} else if len(args.Network) > 0 {
|
||||
result, err = modules.Loadbalancernetworks.ListDescendent2(s, args.Network, params)
|
||||
} else {
|
||||
result, err = modules.Loadbalancernetworks.List(s, params)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(result, modules.Loadbalancernetworks.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func init() {
|
||||
printObject(lb)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerDeleteOptions{}, "lb-delete", "Show lb", func(s *mcclient.ClientSession, opts *options.LoadbalancerDeleteOptions) error {
|
||||
R(&options.LoadbalancerDeleteOptions{}, "lb-delete", "Delete lb", func(s *mcclient.ClientSession, opts *options.LoadbalancerDeleteOptions) error {
|
||||
lb, err := modules.Loadbalancers.Delete(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -56,6 +56,14 @@ func init() {
|
||||
printObject(lb)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerPurgeOptions{}, "lb-purge", "Purge lb", func(s *mcclient.ClientSession, opts *options.LoadbalancerPurgeOptions) error {
|
||||
lb, err := modules.Loadbalancers.PerformAction(s, opts.ID, "purge", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lb)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerActionStatusOptions{}, "lb-status", "Change lb status", func(s *mcclient.ClientSession, opts *options.LoadbalancerActionStatusOptions) error {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
@@ -68,4 +76,12 @@ func init() {
|
||||
printObject(lb)
|
||||
return nil
|
||||
})
|
||||
R(&options.LoadbalancerActionSyncStatusOptions{}, "lb-syncstatus", "Sync lb status", func(s *mcclient.ClientSession, opts *options.LoadbalancerActionSyncStatusOptions) error {
|
||||
lb, err := modules.Loadbalancers.PerformAction(s, opts.ID, "syncstatus", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(lb)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
/**
|
||||
* 创建一条报警规则
|
||||
*/
|
||||
type MeterAlertCreateOptions struct {
|
||||
TYPE string `help:"Alert rule type" choices:"balance|resFee|monthFee"`
|
||||
PROVIDER string `help:"Name of the cloud platform"`
|
||||
ACCOUNT_ID string `help:"ID of the cloud platform"`
|
||||
THRESHOLD float64 `help:"Threshold value of the metric"`
|
||||
COMPARATOR string `help:"Comparison operator for join expressions" choices:">|<|>=|<=|=|!="`
|
||||
RECIPIENTS string `help:"Comma separated recipient ID"`
|
||||
LEVEL string `help:"Alert level" choices:"normal|important|fatal"`
|
||||
CHANNEL string `help:"Ways to send an alarm" choices:"email|mobile"`
|
||||
}
|
||||
R(&MeterAlertCreateOptions{}, "meteralert-create", "Create a meter alert rule", func(s *mcclient.ClientSession, args *MeterAlertCreateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.TYPE), "type")
|
||||
params.Add(jsonutils.NewString(args.PROVIDER), "provider")
|
||||
params.Add(jsonutils.NewString(args.ACCOUNT_ID), "account_id")
|
||||
params.Add(jsonutils.NewFloat(args.THRESHOLD), "threshold")
|
||||
params.Add(jsonutils.NewString(args.COMPARATOR), "comparator")
|
||||
params.Add(jsonutils.NewString(args.RECIPIENTS), "recipients")
|
||||
params.Add(jsonutils.NewString(args.LEVEL), "level")
|
||||
params.Add(jsonutils.NewString(args.CHANNEL), "channel")
|
||||
|
||||
rst, err := modules.MeterAlert.Create(s, params)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printObject(rst)
|
||||
return nil
|
||||
})
|
||||
|
||||
/**
|
||||
* 删除指定ID的报警规则
|
||||
*/
|
||||
type MeterAlertDeleteOptions struct {
|
||||
ID string `help:"ID of alarm"`
|
||||
}
|
||||
R(&MeterAlertDeleteOptions{}, "meteralert-delete", "Delete a meter alert", func(s *mcclient.ClientSession, args *MeterAlertDeleteOptions) error {
|
||||
alarm, e := modules.MeterAlert.Delete(s, args.ID, nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
printObject(alarm)
|
||||
return nil
|
||||
})
|
||||
|
||||
/**
|
||||
* 修改指定ID的报警规则状态
|
||||
*/
|
||||
type MeterAlertUpdateOptions struct {
|
||||
ID string `help:"ID of the meter alert"`
|
||||
STATUS string `help:"Name of the new alarm" choices:"Enabled|Disabled"`
|
||||
}
|
||||
R(&MeterAlertUpdateOptions{}, "meteralert-change-status", "Change status of a meter alert", func(s *mcclient.ClientSession, args *MeterAlertUpdateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.STATUS), "status")
|
||||
|
||||
alarm, err := modules.MeterAlert.Patch(s, args.ID, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(alarm)
|
||||
return nil
|
||||
})
|
||||
|
||||
/**
|
||||
* 列出报警规则
|
||||
*/
|
||||
type MeterAlertListOptions struct {
|
||||
options.BaseListOptions
|
||||
}
|
||||
R(&MeterAlertListOptions{}, "meteralert-list", "List meter alert", func(s *mcclient.ClientSession, args *MeterAlertListOptions) error {
|
||||
var params *jsonutils.JSONDict
|
||||
{
|
||||
var err error
|
||||
params, err = args.BaseListOptions.Params()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
result, err := modules.MeterAlert.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(result, modules.MeterAlert.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -163,7 +163,7 @@ func init() {
|
||||
params.Add(jsonutils.NewString(args.MonitorConfig), "monitor_conf_value")
|
||||
}
|
||||
|
||||
monitor_template_inputs, err := modules.MonitorTemplateInputs.Update(s, args.MONITOR_TEMPLATE_ID, args.MONITOR_INPUT_NAME, params)
|
||||
monitor_template_inputs, err := modules.MonitorTemplateInputs.Update(s, args.MONITOR_TEMPLATE_ID, args.MONITOR_INPUT_NAME, nil, params)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,7 +17,9 @@ func init() {
|
||||
Wire string `help:"search networks belongs to a wire" json:"-"`
|
||||
Vpc string `help:"search networks belongs to a VPC"`
|
||||
Region string `help:"search networks belongs to a CloudRegion" json:"cloudregion"`
|
||||
ServerType string `help:"search networks belongs to a ServerType"`
|
||||
ServerType string `help:"search networks belongs to a ServerType" choices:"guest|baremetal|container|pxe|ipmi"`
|
||||
Private *bool `help:"show private cloud networks only" json:"is_private"`
|
||||
Public *bool `help:"show public cloud networks only" json:"is_public"`
|
||||
}
|
||||
R(&NetworkListOptions{}, "network-list", "List networks", func(s *mcclient.ClientSession, opts *NetworkListOptions) error {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
@@ -41,7 +43,7 @@ func init() {
|
||||
ID string `help:"ID or Name of zone to update"`
|
||||
Name string `help:"Name of zone"`
|
||||
Desc string `metavar:"<DESCRIPTION>" help:"Description"`
|
||||
ServerType string `help:"server type," choices:"baremetal|guest|container"`
|
||||
ServerType string `help:"server type," choices:"baremetal|guest|container|pxe|ipmi"`
|
||||
StartIp string `help:"Start ip"`
|
||||
EndIp string `help:"end ip"`
|
||||
NetMask int64 `help:"Netmask"`
|
||||
@@ -183,7 +185,7 @@ func init() {
|
||||
Gateway string `help:"Default gateway"`
|
||||
VlanId int64 `help:"Vlan ID" default:"1"`
|
||||
AllocPolicy string `help:"Address allocation policy" choices:"none|stepdown|stepup|random"`
|
||||
ServerType string `help:"Server type" choices:"baremetal|guest|container"`
|
||||
ServerType string `help:"Server type" choices:"baremetal|guest|container|pxe|ipmi"`
|
||||
Desc string `help:"Description" metavar:"DESCRIPTION"`
|
||||
}
|
||||
R(&NetworkCreateOptions{}, "network-create", "Create a virtual network", func(s *mcclient.ClientSession, args *NetworkCreateOptions) error {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
//"strings"
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/notify"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
@@ -13,35 +13,38 @@ func init() {
|
||||
/**
|
||||
* 新建一个通知发送任务
|
||||
*/
|
||||
|
||||
type NotificationCreateOptions struct {
|
||||
UID string `help:"The user you wanna sent to (Keystone User ID)"`
|
||||
CONTACTTYPE string `help:"User's contacts type, maybe email|mobile|dingtalk" choices:"email|mobile|dingtalk"`
|
||||
CONTACTTYPE string `help:"User's contacts type, cloud be email|mobile|dingtalk|webconsole" choices:"email|mobile|dingtalk|webconsole"`
|
||||
TOPIC string `help:"Title or topic of the notification"`
|
||||
PRIORITY string `help:"Priority of the notification maybe normal|important|fatal" choices:"normal|important|fatal"`
|
||||
MSG string `help:"The content of the notification"`
|
||||
Remark string `help:"Remark or description of the notification"`
|
||||
Group bool `help:"Send to group"`
|
||||
Channel string `help:"User's contacts type, cloud be email|mobile|dingtalk|webconsole" choices:"email|mobile|dingtalk|webconsole"`
|
||||
}
|
||||
R(&NotificationCreateOptions{}, "notify", "Send a notification to sb", func(s *mcclient.ClientSession, args *NotificationCreateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
msg := notify.SNotifyMessage{}
|
||||
if args.Group {
|
||||
params.Add(jsonutils.NewString(args.UID), "gid")
|
||||
msg.Gid = args.UID
|
||||
} else {
|
||||
params.Add(jsonutils.NewString(args.UID), "uid")
|
||||
}
|
||||
params.Add(jsonutils.NewString(args.CONTACTTYPE), "contact_type")
|
||||
params.Add(jsonutils.NewString(args.TOPIC), "topic")
|
||||
params.Add(jsonutils.NewString(args.PRIORITY), "priority")
|
||||
params.Add(jsonutils.NewString(args.MSG), "msg")
|
||||
if len(args.Remark) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Remark), "remark")
|
||||
msg.Uid = args.UID
|
||||
}
|
||||
|
||||
notification, err := modules.Notifications.Create(s, params)
|
||||
msg.ContactType = []notify.TNotifyChannel{notify.TNotifyChannel(args.CONTACTTYPE)}
|
||||
for _, c := range args.Channel {
|
||||
msg.ContactType = append(msg.ContactType, notify.TNotifyChannel(c))
|
||||
}
|
||||
msg.Topic = args.TOPIC
|
||||
msg.Priority = notify.TNotifyPriority(args.PRIORITY)
|
||||
msg.Msg = args.MSG
|
||||
msg.Remark = args.Remark
|
||||
|
||||
err := notify.Notifications.Send(s, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(notification)
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -60,7 +63,7 @@ func init() {
|
||||
params.Add(jsonutils.NewString(args.Remark), "remark")
|
||||
}
|
||||
|
||||
notification, err := modules.Notifications.Put(s, args.ID, params)
|
||||
notification, err := notify.Notifications.Put(s, args.ID, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -75,12 +78,12 @@ func init() {
|
||||
options.BaseListOptions
|
||||
}
|
||||
R(&NotificationListOptions{}, "notify-list", "List notification history", func(s *mcclient.ClientSession, args *NotificationListOptions) error {
|
||||
result, err := modules.Notifications.List(s, nil)
|
||||
result, err := notify.Notifications.List(s, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printList(result, modules.Notifications.GetColumns(s))
|
||||
printList(result, notify.Notifications.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
func init() {
|
||||
type NetworkReserveIPOptions struct {
|
||||
NETWORK string `help:"IP or name of network"`
|
||||
IP string `help:"IP to reserve"`
|
||||
NOTES string `help:"Why reserve this IP"`
|
||||
NETWORK string `help:"IP or name of network"`
|
||||
NOTES string `help:"Why reserve this IP"`
|
||||
IPS []string `help:"IPs to reserve"`
|
||||
}
|
||||
R(&NetworkReserveIPOptions{}, "network-reserve-ip", "Reserve an IP address from pool", func(s *mcclient.ClientSession, args *NetworkReserveIPOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.IP), "ip")
|
||||
params.Add(jsonutils.NewStringArray(args.IPS), "ips")
|
||||
params.Add(jsonutils.NewString(args.NOTES), "notes")
|
||||
net, err := modules.Networks.PerformAction(s, args.NETWORK, "reserve-ip", params)
|
||||
if err != nil {
|
||||
|
||||
@@ -53,7 +53,7 @@ func init() {
|
||||
})
|
||||
|
||||
R(&SchedtagHostPair{}, "schedtag-host-remove", "Remove a schedtag from a host", func(s *mcclient.ClientSession, args *SchedtagHostPair) error {
|
||||
schedtag, err := modules.Schedtaghosts.Detach(s, args.SCHEDTAG, args.HOST)
|
||||
schedtag, err := modules.Schedtaghosts.Detach(s, args.SCHEDTAG, args.HOST, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ func init() {
|
||||
if params.Size() == 0 {
|
||||
return InvalidUpdateError()
|
||||
}
|
||||
srv, err := modules.Serverdisks.Update(s, args.SERVER, args.DISK, params)
|
||||
srv, err := modules.Serverdisks.Update(s, args.SERVER, args.DISK, nil, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
@@ -31,9 +36,6 @@ func init() {
|
||||
if len(args.Ip) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Ip), "ip_addr")
|
||||
}
|
||||
if len(args.Network) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Network), "network_id")
|
||||
}
|
||||
var result *modules.ListResult
|
||||
var err error
|
||||
if len(args.Server) > 0 {
|
||||
@@ -53,9 +55,14 @@ func init() {
|
||||
type ServerNetworkDetailOptions struct {
|
||||
SERVER string `help:"ID or Name of Server"`
|
||||
NETWORK string `help:"ID or Name of Network"`
|
||||
Mac string `help:"Mac of the guest NIC"`
|
||||
}
|
||||
R(&ServerNetworkDetailOptions{}, "server-network-show", "Show server network details", func(s *mcclient.ClientSession, args *ServerNetworkDetailOptions) error {
|
||||
result, err := modules.Servernetworks.Get(s, args.SERVER, args.NETWORK, nil)
|
||||
query := jsonutils.NewDict()
|
||||
if len(args.Mac) > 0 {
|
||||
query.Add(jsonutils.NewString(args.Mac), "mac")
|
||||
}
|
||||
result, err := modules.Servernetworks.Get(s, args.SERVER, args.NETWORK, query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -66,6 +73,7 @@ func init() {
|
||||
type ServerNetworkUpdateOptions struct {
|
||||
SERVER string `help:"ID or Name of Server"`
|
||||
NETWORK string `help:"ID or Name of Wire"`
|
||||
Mac string `help:"Mac of NIC"`
|
||||
Driver string `help:"Driver model of vNIC" choices:"virtio|e1000|vmxnet3|rtl8139"`
|
||||
Index int64 `help:"Index of NIC" default:"-1"`
|
||||
Ifname string `help:"Interface name of vNIC on host"`
|
||||
@@ -84,7 +92,11 @@ func init() {
|
||||
if params.Size() == 0 {
|
||||
return InvalidUpdateError()
|
||||
}
|
||||
result, err := modules.Servernetworks.Update(s, args.SERVER, args.NETWORK, params)
|
||||
query := jsonutils.NewDict()
|
||||
if len(args.Mac) > 0 {
|
||||
query.Add(jsonutils.NewString(args.Mac), "mac")
|
||||
}
|
||||
result, err := modules.Servernetworks.Update(s, args.SERVER, args.NETWORK, query, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -93,13 +105,25 @@ func init() {
|
||||
})
|
||||
|
||||
type ServerNetworkBWOptions struct {
|
||||
SERVER string `help:"ID or Name of server"`
|
||||
INDEX int64 `help:"Index of NIC"`
|
||||
BW int64 `help:"Bandwidth in Mbps"`
|
||||
SERVER string `help:"ID or Name of server"`
|
||||
MACORIP string `help:"IP, Mac, or Index of NIC"`
|
||||
BW int64 `help:"Bandwidth in Mbps"`
|
||||
}
|
||||
R(&ServerNetworkBWOptions{}, "server-change-bandwidth", "Change server network bandwidth in Mbps", func(s *mcclient.ClientSession, args *ServerNetworkBWOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewInt(args.INDEX), "index")
|
||||
if regutils.MatchMacAddr(args.MACORIP) {
|
||||
params.Add(jsonutils.NewString(args.MACORIP), "mac")
|
||||
} else if regutils.MatchIP4Addr(args.MACORIP) {
|
||||
params.Add(jsonutils.NewString(args.MACORIP), "ip_addr")
|
||||
} else if regutils.MatchInteger(args.MACORIP) {
|
||||
index, err := strconv.ParseInt(args.MACORIP, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Add(jsonutils.NewInt(index), "index")
|
||||
} else {
|
||||
return fmt.Errorf("Please specify Ip or Mac")
|
||||
}
|
||||
params.Add(jsonutils.NewInt(args.BW), "bandwidth")
|
||||
server, err := modules.Servers.PerformAction(s, args.SERVER, "change-bandwidth", params)
|
||||
if err != nil {
|
||||
@@ -126,15 +150,30 @@ func init() {
|
||||
|
||||
type ServerDetachNetworkOptions struct {
|
||||
SERVER string `help:"ID or Name of server"`
|
||||
NETWORK string `help:"ID or Name of network to detach"`
|
||||
MACORIP string `help:"Mac Or IP of NIC"`
|
||||
Reserve bool `help:"Put the release IP address into reserved address pool"`
|
||||
}
|
||||
R(&ServerDetachNetworkOptions{}, "server-detach-network", "Detach the virtual network fron a virtual server", func(s *mcclient.ClientSession, args *ServerDetachNetworkOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.NETWORK), "net_id")
|
||||
// params.Add(jsonutils.NewString(args.NETWORK), "net_id")
|
||||
if args.Reserve {
|
||||
params.Add(jsonutils.JSONTrue, "reserve")
|
||||
}
|
||||
if regutils.MatchMacAddr(args.MACORIP) {
|
||||
params.Add(jsonutils.NewString(args.MACORIP), "mac")
|
||||
} else if regutils.MatchIP4Addr(args.MACORIP) {
|
||||
params.Add(jsonutils.NewString(args.MACORIP), "ip_addr")
|
||||
} else if regutils.MatchInteger(args.MACORIP) {
|
||||
index, err := strconv.ParseInt(args.MACORIP, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Add(jsonutils.NewInt(index), "index")
|
||||
} else if len(args.MACORIP) > 0 {
|
||||
params.Add(jsonutils.NewString(args.MACORIP), "net_id")
|
||||
} else {
|
||||
return fmt.Errorf("Please specify Ip or Mac")
|
||||
}
|
||||
srv, err := modules.Servers.PerformAction(s, args.SERVER, "detachnetwork", params)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -143,4 +182,37 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type ServerChangeIPAddressOptions struct {
|
||||
SERVER string `help:"ID or Name of server"`
|
||||
MACORIP string `help:"Mac Or IP of NIC"`
|
||||
NETDESC string `help:"Network description"`
|
||||
Reserve bool `help:"Put the release IP address into reserved address pool"`
|
||||
}
|
||||
R(&ServerChangeIPAddressOptions{}, "server-change-ipaddr", "Change ipaddr of a virtual server", func(s *mcclient.ClientSession, args *ServerChangeIPAddressOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
if args.Reserve {
|
||||
params.Add(jsonutils.JSONTrue, "reserve")
|
||||
}
|
||||
if regutils.MatchMacAddr(args.MACORIP) {
|
||||
params.Add(jsonutils.NewString(args.MACORIP), "mac")
|
||||
} else if regutils.MatchIP4Addr(args.MACORIP) {
|
||||
params.Add(jsonutils.NewString(args.MACORIP), "ip_addr")
|
||||
} else if regutils.MatchInteger(args.MACORIP) {
|
||||
index, err := strconv.ParseInt(args.MACORIP, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Add(jsonutils.NewInt(index), "index")
|
||||
} else {
|
||||
return fmt.Errorf("Please specify Ip or Mac")
|
||||
}
|
||||
params.Add(jsonutils.NewString(args.NETDESC), "net_desc")
|
||||
srv, err := modules.Servers.PerformAction(s, args.SERVER, "change-ipaddr", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(srv)
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -166,6 +166,15 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&options.ServerDeleteBackupOptions{}, "server-delete-backup", "Guest delete backup", func(s *mcclient.ClientSession, opts *options.ServerDeleteBackupOptions) error {
|
||||
ret, err := modules.Servers.PerformAction(s, opts.ID, "delete-backup", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&options.ServerStopOptions{}, "server-stop", "Stop servers", func(s *mcclient.ClientSession, opts *options.ServerStopOptions) error {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
@@ -560,10 +569,15 @@ func init() {
|
||||
})
|
||||
|
||||
type ServerDissociateEipOptions struct {
|
||||
ID string `help:"ID or name of server"`
|
||||
ID string `help:"ID or name of server" json:"-"`
|
||||
AutoDelete bool `help:"automatically delete the dissociate EIP" json:"auto_delete,omitfalse"`
|
||||
}
|
||||
R(&ServerDissociateEipOptions{}, "server-dissociate-eip", "Dissociate an eip from a server", func(s *mcclient.ClientSession, args *ServerDissociateEipOptions) error {
|
||||
result, err := modules.Servers.PerformAction(s, args.ID, "dissociate-eip", nil)
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Servers.PerformAction(s, args.ID, "dissociate-eip", params)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func init() {
|
||||
if params.Size() == 0 {
|
||||
return InvalidUpdateError()
|
||||
}
|
||||
result, err := modules.Storagecachedimages.Update(s, args.STORAGECACHE, args.IMAGE, params)
|
||||
result, err := modules.Storagecachedimages.Update(s, args.STORAGECACHE, args.IMAGE, nil, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
func init() {
|
||||
type StoragecacheListOptions struct {
|
||||
options.BaseListOptions
|
||||
|
||||
CloudregionId string `help:"cloudregion id"`
|
||||
}
|
||||
R(&StoragecacheListOptions{}, "storage-cache-list", "List storage caches", func(s *mcclient.ClientSession, opts *StoragecacheListOptions) error {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
@@ -71,7 +73,7 @@ func init() {
|
||||
type StorageUncacheImageActionOptions struct {
|
||||
ID string `help:"ID or name of storage"`
|
||||
IMAGE string `help:"ID or name of image"`
|
||||
Force bool `help:"Force uncache, even if the image exists in cache"`
|
||||
Force bool `help:"Force uncache, even if the image exists in cache is invalid"`
|
||||
}
|
||||
R(&StorageUncacheImageActionOptions{}, "storagecache-uncache-image", "Ask a storage cache to remove image from its cache", func(s *mcclient.ClientSession, args *StorageUncacheImageActionOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/hostman"
|
||||
|
||||
func main() {
|
||||
var srv = hostman.SHostService{}
|
||||
srv.StartService()
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/util/huawei"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
_ "yunion.io/x/onecloud/pkg/util/huawei/shell"
|
||||
)
|
||||
|
||||
type BaseOptions struct {
|
||||
Help bool `help:"Show help" default:"false"`
|
||||
Debug bool `help:"Show debug" default:"false"`
|
||||
CloudEnv string `help:"Cloud environment" default:"$HUAWEI_CLOUD_ENV" choices:"ChinaCloud|InternationalCloud"`
|
||||
AccessKey string `help:"Access key" default:"$HUAWEI_ACCESS_KEY"`
|
||||
Secret string `help:"Secret" default:"$HUAWEI_SECRET"`
|
||||
RegionId string `help:"RegionId" default:"$HUAWEI_REGION"`
|
||||
ProjectId string `help:"RegionId" default:"$HUAWEI_PROJECT"`
|
||||
SUBCOMMAND string `help:"huaweicli subcommand" subcommand:"true"`
|
||||
}
|
||||
|
||||
func getSubcommandParser() (*structarg.ArgumentParser, error) {
|
||||
parse, e := structarg.NewArgumentParser(&BaseOptions{},
|
||||
"huaweicli",
|
||||
"Command-line interface to huawei API.",
|
||||
`See "huaweicli 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) {
|
||||
log.Errorf("%s", e)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func newClient(options *BaseOptions) (*huawei.SRegion, error) {
|
||||
if len(options.AccessKey) == 0 {
|
||||
return nil, fmt.Errorf("Missing accessKey")
|
||||
}
|
||||
|
||||
if len(options.Secret) == 0 {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
account := ""
|
||||
if len(options.ProjectId) > 0 {
|
||||
account = options.AccessKey + "/" + options.ProjectId
|
||||
} else {
|
||||
account = options.AccessKey
|
||||
}
|
||||
|
||||
cli, err := huawei.NewHuaweiClient("", "", options.CloudEnv, account, options.Secret, options.Debug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
region := cli.GetRegion(options.RegionId)
|
||||
if region == nil {
|
||||
return nil, fmt.Errorf("No such region %s", options.RegionId)
|
||||
}
|
||||
|
||||
return region, 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())
|
||||
} else {
|
||||
subcmd := parser.GetSubcommand()
|
||||
subparser := subcmd.GetSubParser()
|
||||
if e != nil {
|
||||
if subparser != nil {
|
||||
fmt.Print(subparser.Usage())
|
||||
} else {
|
||||
fmt.Print(parser.Usage())
|
||||
}
|
||||
showErrorAndExit(e)
|
||||
} else {
|
||||
suboptions := subparser.Options()
|
||||
if options.SUBCOMMAND == "help" {
|
||||
e = subcmd.Invoke(suboptions)
|
||||
} else {
|
||||
var region *huawei.SRegion
|
||||
region, e = newClient(options)
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
e = subcmd.Invoke(region, suboptions)
|
||||
}
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
|
||||
_ "yunion.io/x/onecloud/pkg/util/ipmitool/shell"
|
||||
)
|
||||
|
||||
type BaseOptions struct {
|
||||
Help bool `help:"Show help" short-token:"h"`
|
||||
MODE string `help:"Execute command mode" choices:"ssh|rmcp"`
|
||||
HOST string `help:"IP address of remote host"`
|
||||
PASSWD string `help:"Password"`
|
||||
User string `help:"Username" short-token:"u" default:"root"`
|
||||
Port int `help:"Remote service port"`
|
||||
SUBCOMMAND string `help:"ipmicli subcommand" subcommand:"true"`
|
||||
}
|
||||
|
||||
func showErrorAndExit(err error) {
|
||||
log.Errorf("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func getSubcommandParser() (*structarg.ArgumentParser, error) {
|
||||
parser, err := structarg.NewArgumentParser(
|
||||
&BaseOptions{},
|
||||
"ipmicli",
|
||||
"Command-line interface to ipmitool",
|
||||
`See "ipmicli help COMMAND" for help on a specific command.`,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subcmd := parser.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 parser, nil
|
||||
}
|
||||
|
||||
func newExecutor(options *BaseOptions) (ipmitool.IPMIExecutor, error) {
|
||||
if options.MODE == "ssh" {
|
||||
port := 22
|
||||
if options.Port > 0 {
|
||||
port = options.Port
|
||||
}
|
||||
sshCli, err := ssh.NewClient(options.HOST, port, options.User, options.PASSWD, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ipmitool.NewSSHIPMI(sshCli), nil
|
||||
}
|
||||
if options.MODE == "rmcp" {
|
||||
port := 623
|
||||
if options.Port > 0 {
|
||||
port = options.Port
|
||||
}
|
||||
return ipmitool.NewLanPlusIPMIWithPort(options.HOST, options.User, options.PASSWD, port), nil
|
||||
}
|
||||
return nil, fmt.Errorf("Unsupported mode: %s", options.MODE)
|
||||
}
|
||||
|
||||
func main() {
|
||||
parser, err := getSubcommandParser()
|
||||
if err != nil {
|
||||
showErrorAndExit(err)
|
||||
}
|
||||
|
||||
err = 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 err != nil {
|
||||
if subparser != nil {
|
||||
fmt.Print(subparser.Usage())
|
||||
} else {
|
||||
fmt.Print(parser.Usage())
|
||||
}
|
||||
showErrorAndExit(err)
|
||||
return
|
||||
}
|
||||
|
||||
suboptions := subparser.Options()
|
||||
var args []interface{}
|
||||
if options.SUBCOMMAND == "help" {
|
||||
args = append(args, suboptions)
|
||||
} else {
|
||||
executor, err := newExecutor(options)
|
||||
if err != nil {
|
||||
showErrorAndExit(err)
|
||||
}
|
||||
args = append(args, executor, suboptions)
|
||||
}
|
||||
err = subcmd.Invoke(args...)
|
||||
if err != nil {
|
||||
showErrorAndExit(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/logger/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
service.StartService()
|
||||
}
|
||||
+50
-20
@@ -6,7 +6,6 @@ import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -15,6 +14,7 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/trace"
|
||||
"yunion.io/x/pkg/util/signalutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appctx"
|
||||
@@ -40,6 +40,7 @@ type Application struct {
|
||||
cors *Cors
|
||||
middlewares []MiddlewareFunc
|
||||
|
||||
isExiting bool
|
||||
idleConnsClosed chan struct{}
|
||||
}
|
||||
|
||||
@@ -332,44 +333,73 @@ func (app *Application) initServer(addr string) *http.Server {
|
||||
|
||||
func (app *Application) registerCleanShutdown(s *http.Server, onStop func()) {
|
||||
app.idleConnsClosed = make(chan struct{})
|
||||
go func() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
|
||||
log.Infof("Close signal received: %+v", <-c)
|
||||
|
||||
// dump goroutine stack
|
||||
signalutils.RegisterSignal(func() {
|
||||
utils.DumpAllGoroutineStack(log.Logger().Out)
|
||||
}, syscall.SIGUSR1)
|
||||
|
||||
quitSignals := []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM}
|
||||
signalutils.RegisterSignal(func() {
|
||||
if app.isExiting {
|
||||
log.Infof("Quit signal received!!! clean up in progress, be patient...")
|
||||
return
|
||||
}
|
||||
app.isExiting = true
|
||||
log.Infof("Quit signal received!!! do cleanup...")
|
||||
|
||||
if err := s.Shutdown(context.Background()); err != nil {
|
||||
// Error from closing listeners, or context timeout:
|
||||
log.Errorf("HTTP server Shutdown: %v", err)
|
||||
}
|
||||
onStop()
|
||||
|
||||
if onStop != nil {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("app exiting error: %s", r)
|
||||
}
|
||||
}()
|
||||
onStop()
|
||||
}()
|
||||
}
|
||||
close(app.idleConnsClosed)
|
||||
}()
|
||||
}, quitSignals...)
|
||||
|
||||
signalutils.StartTrap()
|
||||
}
|
||||
|
||||
func (app *Application) waitCleanShutdown() {
|
||||
<-app.idleConnsClosed
|
||||
log.Infof("Service stopped.")
|
||||
}
|
||||
|
||||
func (app *Application) ListenAndServe(addr string, onStop func()) {
|
||||
func (app *Application) ListenAndServe(addr string) {
|
||||
app.ListenAndServeWithCleanup(addr, nil)
|
||||
}
|
||||
|
||||
func (app *Application) ListenAndServeTLS(addr string, certFile, keyFile string) {
|
||||
app.ListenAndServeTLSWithCleanup(addr, certFile, keyFile, nil)
|
||||
}
|
||||
|
||||
func (app *Application) ListenAndServeWithCleanup(addr string, onStop func()) {
|
||||
app.ListenAndServeTLSWithCleanup(addr, "", "", onStop)
|
||||
}
|
||||
|
||||
func (app *Application) ListenAndServeTLSWithCleanup(addr string, certFile, keyFile string, onStop func()) {
|
||||
s := app.initServer(addr)
|
||||
app.registerCleanShutdown(s, onStop)
|
||||
err := s.ListenAndServe()
|
||||
var err error
|
||||
if len(certFile) == 0 && len(keyFile) == 0 {
|
||||
err = s.ListenAndServe()
|
||||
} else {
|
||||
err = s.ListenAndServeTLS(certFile, keyFile)
|
||||
}
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("ListAndServer fail: %s", err)
|
||||
}
|
||||
app.waitCleanShutdown()
|
||||
}
|
||||
|
||||
func (app *Application) ListenAndServeTLS(addr string, certFile, keyFile string, onStop func()) {
|
||||
s := app.initServer(addr)
|
||||
app.registerCleanShutdown(s, onStop)
|
||||
err := s.ListenAndServeTLS(certFile, keyFile)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("ListAndServerTLS fail: %s", err)
|
||||
}
|
||||
app.waitCleanShutdown()
|
||||
}
|
||||
|
||||
func isJsonContentType(r *http.Request) bool {
|
||||
contType := strings.ToLower(r.Header.Get("Content-Type"))
|
||||
if strings.HasPrefix(contType, "application/json") {
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/pxe"
|
||||
"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/util/procutils"
|
||||
)
|
||||
|
||||
var (
|
||||
baremetalAgent *SBaremetalAgent
|
||||
)
|
||||
|
||||
type SZone struct {
|
||||
Name string `json:"name"`
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type SBaremetalAgent struct {
|
||||
PXEServer *pxe.Server
|
||||
ListenInterface *net.Interface
|
||||
AgentId string
|
||||
AgentName string
|
||||
Zone *SZone
|
||||
Manager *SBaremetalManager
|
||||
}
|
||||
|
||||
func newBaremetalAgent() (*SBaremetalAgent, error) {
|
||||
iface, err := net.InterfaceByName(o.Options.ListenInterface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ips, err := getIfaceIPs(iface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return nil, fmt.Errorf("Interface %s ip address not found", o.Options.ListenInterface)
|
||||
}
|
||||
log.Debugf("Interface %s ip address: %v", iface.Name, ips)
|
||||
|
||||
agent := &SBaremetalAgent{
|
||||
ListenInterface: iface,
|
||||
}
|
||||
return agent, nil
|
||||
}
|
||||
|
||||
func GetAdminSession() *mcclient.ClientSession {
|
||||
return auth.GetAdminSession(context.TODO(), o.Options.Region, "v2")
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetListenIPs() ([]net.IP, error) {
|
||||
ips, err := getIfaceIPs(agent.ListenInterface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return nil, fmt.Errorf("Interface %s ip address not found", agent.ListenInterface.Name)
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetListenIP() (net.IP, error) {
|
||||
ips, err := agent.GetListenIPs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if o.Options.ListenAddress == "" {
|
||||
return ips[0], nil
|
||||
}
|
||||
if o.Options.ListenAddress == "0.0.0.0" {
|
||||
return net.ParseIP(o.Options.ListenAddress), nil
|
||||
}
|
||||
for _, ip := range ips {
|
||||
if ip.String() == o.Options.ListenAddress {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Not found ListenAddress %s on %s", o.Options.ListenAddress, o.Options.ListenInterface)
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetAccessIP() (net.IP, error) {
|
||||
ips, err := agent.GetListenIPs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if o.Options.AccessAddress == "" {
|
||||
return ips[0], nil
|
||||
}
|
||||
for _, ip := range ips {
|
||||
if ip.String() == o.Options.AccessAddress {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Not found AccessAddress %s on %s", o.Options.AccessAddress, o.Options.ListenInterface)
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetDHCPServerIP() (net.IP, error) {
|
||||
listenIP := o.Options.ListenAddress
|
||||
if len(listenIP) == 0 || listenIP == "0.0.0.0" {
|
||||
return agent.GetAccessIP()
|
||||
}
|
||||
return agent.GetListenIP()
|
||||
}
|
||||
|
||||
func getIfaceIPs(iface *net.Interface) ([]net.IP, error) {
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ips := make([]net.IP, 0)
|
||||
for _, a := range addrs {
|
||||
if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil {
|
||||
ips = append(ips, ipnet.IP)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) startRegister() {
|
||||
if agent.AgentId != "" {
|
||||
return
|
||||
}
|
||||
|
||||
var delayRetryTime time.Duration = 30 * time.Second
|
||||
|
||||
for {
|
||||
err := agent.register()
|
||||
if err != nil {
|
||||
log.Errorf("Register error: %v, retry after %s...", err, delayRetryTime)
|
||||
time.Sleep(delayRetryTime)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) register() error {
|
||||
session := GetAdminSession()
|
||||
var err error
|
||||
err = agent.fetchZone(session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = agent.createOrUpdateBaremetalAgent(session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("Baremetal %s:%s register success, do offline", agent.AgentName, agent.AgentId)
|
||||
err = agent.doOffline(session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
agent.tuneSystem()
|
||||
|
||||
manager, err := NewBaremetalManager(agent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("New baremetal manager error: %v", err)
|
||||
}
|
||||
|
||||
err = manager.loadConfigs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Baremetal manager load config error: %v", err)
|
||||
}
|
||||
|
||||
agent.Manager = manager
|
||||
agent.startPXEServices(manager)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetManager() *SBaremetalManager {
|
||||
return agent.Manager
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) getZoneByIP(session *mcclient.ClientSession) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
listenIP, err := agent.GetListenIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params.Add(jsonutils.NewString(listenIP.String()), "ip")
|
||||
networks, err := modules.Networks.List(session, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(networks.Data) == 0 {
|
||||
return nil, fmt.Errorf("Not found networks by agent listen ip: %s", listenIP)
|
||||
}
|
||||
wireId, err := networks.Data[0].GetString("wire_id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wire, err := modules.Wires.Get(session, wireId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zoneId, err := wire.GetString("zone_id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zone, err := modules.Zones.Get(session, zoneId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) fetchZone(session *mcclient.ClientSession) error {
|
||||
zoneName := o.Options.Zone
|
||||
var zoneInfoObj jsonutils.JSONObject
|
||||
var err error
|
||||
if zoneName != "" {
|
||||
zoneInfoObj, err = modules.Zones.Get(session, zoneName, nil)
|
||||
} else {
|
||||
zoneInfoObj, err = agent.getZoneByIP(session)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zone := SZone{}
|
||||
err = zoneInfoObj.Unmarshal(&zone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
agent.Zone = &zone
|
||||
return nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) createOrUpdateBaremetalAgent(session *mcclient.ClientSession) error {
|
||||
params := jsonutils.NewDict()
|
||||
naccessIP, err := agent.GetAccessIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Add(jsonutils.NewString(naccessIP.String()), "access_ip")
|
||||
ret, err := modules.Baremetalagents.List(session, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
cloudObj jsonutils.JSONObject
|
||||
agentId string
|
||||
agentName string
|
||||
)
|
||||
// create or update BaremetalAgent
|
||||
if len(ret.Data) == 0 {
|
||||
cloudObj, err = agent.createBaremetalAgent(session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
cloudBmAgent := ret.Data[0]
|
||||
accessIP, _ := cloudBmAgent.GetString("access_ip")
|
||||
managerUri, _ := cloudBmAgent.GetString("manager_uri")
|
||||
zoneId, _ := cloudBmAgent.GetString("zone_id")
|
||||
agentId, _ := cloudBmAgent.GetString("id")
|
||||
if naccessIP.String() != accessIP ||
|
||||
agent.GetManagerUri() != managerUri ||
|
||||
zoneId != agent.Zone.Id {
|
||||
cloudObj, err = agent.updateBaremetalAgent(session, agentId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
cloudObj = cloudBmAgent
|
||||
}
|
||||
}
|
||||
|
||||
agentId, err = cloudObj.GetString("id")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
agentName, err = cloudObj.GetString("name")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
agent.AgentId = agentId
|
||||
agent.AgentName = agentName
|
||||
return nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) GetManagerUri() string {
|
||||
accessIP, _ := agent.GetAccessIP()
|
||||
proto := "http"
|
||||
if o.Options.EnableSsl {
|
||||
proto = "https"
|
||||
}
|
||||
return fmt.Sprintf("%s://%s:%d", proto, accessIP, o.Options.Port)
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) getCreateUpdateInfo() (jsonutils.JSONObject, error) {
|
||||
accessIP, err := agent.GetAccessIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params := jsonutils.NewDict()
|
||||
if agent.AgentId == "" {
|
||||
params.Add(jsonutils.NewString(fmt.Sprintf("baremetal_%s", accessIP)), "name")
|
||||
}
|
||||
params.Add(jsonutils.NewString(accessIP.String()), "access_ip")
|
||||
params.Add(jsonutils.NewString(agent.GetManagerUri()), "manager_uri")
|
||||
params.Add(jsonutils.NewString(agent.Zone.Id), "zone_id")
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) createBaremetalAgent(session *mcclient.ClientSession) (jsonutils.JSONObject, error) {
|
||||
params, err := agent.getCreateUpdateInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return modules.Baremetalagents.Create(session, params)
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) updateBaremetalAgent(session *mcclient.ClientSession, id string) (jsonutils.JSONObject, error) {
|
||||
params, err := agent.getCreateUpdateInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return modules.Baremetalagents.Update(session, id, params)
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) doOffline(session *mcclient.ClientSession) error {
|
||||
_, err := modules.Baremetalagents.PerformAction(session, agent.AgentId, "offline", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) doOnline(session *mcclient.ClientSession) error {
|
||||
_, err := modules.Baremetalagents.PerformAction(session, agent.AgentId, "online", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) tuneSystem() {
|
||||
agent.disableUDPOffloading()
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) disableUDPOffloading() {
|
||||
log.Infof("Disable UDP offloading")
|
||||
offTx := procutils.NewCommand("ethtool", "--offload", o.Options.ListenInterface, "tx", "off")
|
||||
offTx.Run()
|
||||
offGso := procutils.NewCommand("ethtool", "-K", o.Options.ListenInterface, "gso", "off")
|
||||
offGso.Run()
|
||||
}
|
||||
|
||||
func (agent *SBaremetalAgent) startPXEServices(manager *SBaremetalManager) {
|
||||
listenIP, err := agent.GetListenIP()
|
||||
if err != nil {
|
||||
log.Fatalf("Get listen ip address error: %v", err)
|
||||
}
|
||||
agent.PXEServer = &pxe.Server{
|
||||
TFTPRootDir: o.Options.TftpRoot,
|
||||
Address: listenIP.String(),
|
||||
BaremetalManager: manager,
|
||||
}
|
||||
go func() {
|
||||
err := agent.PXEServer.Serve()
|
||||
if err != nil {
|
||||
log.Fatalf("Start PXE server error: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func Start() error {
|
||||
var err error
|
||||
if baremetalAgent != nil {
|
||||
log.Warningf("Global baremetalAgent already start")
|
||||
return nil
|
||||
}
|
||||
baremetalAgent, err = newBaremetalAgent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baremetalAgent.startRegister()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetBaremetalAgent() *SBaremetalAgent {
|
||||
return baremetalAgent
|
||||
}
|
||||
|
||||
func GetBaremetalManager() *SBaremetalManager {
|
||||
return GetBaremetalAgent().GetManager()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package baremetal // import "yunion.io/x/onecloud/pkg/baremetal"
|
||||
@@ -0,0 +1,48 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
)
|
||||
|
||||
var delayTaskWorkerMan *appsrv.SWorkerManager
|
||||
|
||||
func init() {
|
||||
delayTaskWorkerMan = appsrv.NewWorkerManager("DelayTaskWorkerManager", 8, 1024, false)
|
||||
}
|
||||
|
||||
type ProcessFunc func(data jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
|
||||
type delayTask struct {
|
||||
process ProcessFunc
|
||||
taskId string
|
||||
session *mcclient.ClientSession
|
||||
data jsonutils.JSONObject
|
||||
}
|
||||
|
||||
func newDelayTask(process ProcessFunc, session *mcclient.ClientSession, taskId string, data jsonutils.JSONObject) *delayTask {
|
||||
return &delayTask{
|
||||
process: process,
|
||||
taskId: taskId,
|
||||
session: session,
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func DelayProcess(process ProcessFunc, session *mcclient.ClientSession, taskId string, data jsonutils.JSONObject) {
|
||||
delayTaskWorkerMan.Run(func() {
|
||||
executeDelayProcess(newDelayTask(process, session, taskId, data))
|
||||
}, nil, nil)
|
||||
}
|
||||
|
||||
func executeDelayProcess(task *delayTask) {
|
||||
ret, err := task.process(task.data)
|
||||
if err != nil {
|
||||
modules.ComputeTasks.TaskFailed(task.session, task.taskId, err)
|
||||
return
|
||||
}
|
||||
modules.ComputeTasks.TaskComplete(task.session, task.taskId, ret)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package handler // import "yunion.io/x/onecloud/pkg/baremetal/handler"
|
||||
@@ -0,0 +1,153 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/baremetal"
|
||||
baremetaltypes "yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
)
|
||||
|
||||
func InitHandlers(app *appsrv.Application) {
|
||||
initBaremetalsHandler(app)
|
||||
}
|
||||
|
||||
func initBaremetalsHandler(app *appsrv.Application) {
|
||||
// baremetal actions handler
|
||||
app.AddHandler("GET", bmActionPrefix("notify"), bmObjMiddleware(handleBaremetalNotify))
|
||||
app.AddHandler("POST", bmActionPrefix("maintenance"), bmObjMiddleware(handleBaremetalMaintenance))
|
||||
app.AddHandler("POST", bmActionPrefix("unmaintenance"), bmObjMiddleware(handleBaremetalUnmaintenance))
|
||||
app.AddHandler("POST", bmActionPrefix("delete"), bmObjMiddleware(handleBaremetalDelete))
|
||||
app.AddHandler("POST", bmActionPrefix("syncstatus"), bmObjMiddleware(handleBaremetalSyncStatus))
|
||||
app.AddHandler("POST", bmActionPrefix("sync-config"), bmObjMiddleware(handleBaremetalSyncConfig))
|
||||
app.AddHandler("POST", bmActionPrefix("sync-ipmi"), bmObjMiddleware(handleBaremetalSyncIPMI))
|
||||
app.AddHandler("POST", bmActionPrefix("prepare"), bmObjMiddleware(handleBaremetalPrepare))
|
||||
app.AddHandler("POST", bmActionPrefix("reset-bmc"), bmObjMiddleware(handleBaremetalResetBMC))
|
||||
|
||||
// server actions handler
|
||||
app.AddHandler("POST", srvActionPrefix("create"), srvClassMiddleware(handleServerCreate))
|
||||
app.AddHandler("POST", srvActionPrefix("deploy"), srvObjMiddleware(handleServerDeploy))
|
||||
app.AddHandler("POST", srvActionPrefix("rebuild"), srvObjMiddleware(handleServerRebuild))
|
||||
app.AddHandler("POST", srvActionPrefix("start"), srvObjMiddleware(handleServerStart))
|
||||
app.AddHandler("POST", srvActionPrefix("stop"), srvObjMiddleware(handleServerStop))
|
||||
app.AddHandler("POST", srvActionPrefix("reset"), srvObjMiddleware(handleServerReset))
|
||||
app.AddHandler("POST", srvActionPrefix("status"), srvObjMiddleware(handleServerStatus))
|
||||
app.AddHandler("DELETE", srvIdPrefix(), srvObjMiddleware(handleServerDelete))
|
||||
}
|
||||
|
||||
func handleBaremetalNotify(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
key, err := ctx.Query().GetString("key")
|
||||
if err != nil {
|
||||
ctx.ResponseError(httperrors.NewInputParameterError("Not found key in query"))
|
||||
return
|
||||
}
|
||||
remoteAddr := ctx.RequestRemoteIP()
|
||||
err = bm.SaveSSHConfig(remoteAddr, key)
|
||||
if err != nil {
|
||||
log.Errorf("Save baremetal %s ssh config: %v", bm.GetId(), err)
|
||||
}
|
||||
|
||||
// execute BaremetalServerPrepareTask
|
||||
task := bm.GetTask()
|
||||
if task != nil {
|
||||
task.SSHExecute(task, remoteAddr, key, nil)
|
||||
}
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalMaintenance(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
bm.StartBaremetalMaintenanceTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalUnmaintenance(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
bm.StartBaremetalUnmaintenanceTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalDelete(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
ctx.DelayProcess(bm.DelayedRemove, nil)
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalSyncStatus(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
ctx.DelayProcess(bm.DelayedSyncStatus, nil)
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalSyncConfig(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
ctx.DelayProcess(bm.DelayedSyncDesc, nil)
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalSyncIPMI(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
ctx.DelayProcess(bm.DelayedSyncIPMIInfo, nil)
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalPrepare(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
bm.StartBaremetalReprepareTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleBaremetalResetBMC(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
bm.StartBaremetalResetBMCTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleServerCreate(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
err := bm.StartServerCreateTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
if err != nil {
|
||||
ctx.ResponseError(httperrors.NewGeneralError(err))
|
||||
return
|
||||
}
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleServerDelete(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremetaltypes.IBaremetalServer) {
|
||||
bm.StartServerDestroyTask(ctx.UserCred(), ctx.TaskId(), nil)
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleServerDeploy(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremetaltypes.IBaremetalServer) {
|
||||
if err := bm.StartServerDeployTask(ctx.UserCred(), ctx.TaskId(), ctx.Data()); err != nil {
|
||||
ctx.ResponseError(httperrors.NewGeneralError(err))
|
||||
return
|
||||
}
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleServerRebuild(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremetaltypes.IBaremetalServer) {
|
||||
if err := bm.StartServerRebuildTask(ctx.UserCred(), ctx.TaskId(), ctx.Data()); err != nil {
|
||||
ctx.ResponseError(httperrors.NewGeneralError(err))
|
||||
return
|
||||
}
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleServerStart(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremetaltypes.IBaremetalServer) {
|
||||
if err := bm.StartServerStartTask(ctx.UserCred(), ctx.TaskId(), ctx.Data()); err != nil {
|
||||
ctx.ResponseError(httperrors.NewGeneralError(err))
|
||||
return
|
||||
}
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleServerReset(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremetaltypes.IBaremetalServer) {
|
||||
ctx.DelayProcess(bm.DelayedServerReset, nil)
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
func handleServerStatus(ctx *Context, bm *baremetal.SBaremetalInstance, _ baremetaltypes.IBaremetalServer) {
|
||||
ctx.DelayProcess(bm.DelayedServerStatus, nil)
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/baremetal"
|
||||
baremetaltypes "yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
)
|
||||
|
||||
const (
|
||||
BM_PREFIX = "baremetals"
|
||||
SERVER_PREFIX = "servers"
|
||||
|
||||
PARAMS_BMID_KEY = "<bm_id>"
|
||||
PARAMS_SRVID_KEY = "<srv_id>"
|
||||
)
|
||||
|
||||
func bmIdPrefix() string {
|
||||
// baremetals/<bm_id>
|
||||
return fmt.Sprintf("%s/%s", BM_PREFIX, PARAMS_BMID_KEY)
|
||||
}
|
||||
|
||||
func bmActionPrefix(action string) string {
|
||||
// baremetals/<bm_id>/action
|
||||
return fmt.Sprintf("%s/%s", bmIdPrefix(), action)
|
||||
}
|
||||
|
||||
func srvIdPrefix() string {
|
||||
// baremetals/<bm_id>/servers/<srv_id>
|
||||
return fmt.Sprintf("%s/%s/%s", bmIdPrefix(), SERVER_PREFIX, PARAMS_SRVID_KEY)
|
||||
}
|
||||
|
||||
func srvActionPrefix(action string) string {
|
||||
// baremetals/<bm_id>/servers/<srv_id>/action
|
||||
return fmt.Sprintf("%s/%s", srvIdPrefix(), action)
|
||||
}
|
||||
|
||||
type handlerFunc func(ctx *Context)
|
||||
|
||||
func authMiddleware(h handlerFunc) appsrv.FilterHandler {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
newCtx := NewContext(ctx, w, r)
|
||||
h(newCtx)
|
||||
}
|
||||
}
|
||||
|
||||
type bmObjHandlerFunc func(ctx *Context, bm *baremetal.SBaremetalInstance)
|
||||
|
||||
func bmObjMiddleware(h bmObjHandlerFunc) appsrv.FilterHandler {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
newCtx := NewContext(ctx, w, r)
|
||||
bmId := newCtx.Params()[PARAMS_BMID_KEY]
|
||||
baremetal := newCtx.GetBaremetalManager().GetBaremetalById(bmId)
|
||||
if baremetal == nil {
|
||||
newCtx.ResponseError(httperrors.NewNotFoundError("Not found baremetal by id: %s", bmId))
|
||||
return
|
||||
}
|
||||
h(newCtx, baremetal)
|
||||
}
|
||||
}
|
||||
|
||||
type srvObjHandlerFunc func(ctx *Context, bm *baremetal.SBaremetalInstance, srv baremetaltypes.IBaremetalServer)
|
||||
|
||||
func srvClassMiddleware(h bmObjHandlerFunc) appsrv.FilterHandler {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
newCtx := NewContext(ctx, w, r)
|
||||
bmId := newCtx.Params()[PARAMS_BMID_KEY]
|
||||
//srvId := newCtx.Params()[PARAMS_SRVID_KEY]
|
||||
baremetal := newCtx.GetBaremetalManager().GetBaremetalById(bmId)
|
||||
if baremetal == nil {
|
||||
newCtx.ResponseError(httperrors.NewNotFoundError("Not found baremetal by id: %s", bmId))
|
||||
return
|
||||
}
|
||||
if baremetal.GetServerId() != "" {
|
||||
newCtx.ResponseError(httperrors.NewNotAcceptableError("Baremetal %s occupied", bmId))
|
||||
return
|
||||
}
|
||||
h(newCtx, baremetal)
|
||||
}
|
||||
}
|
||||
|
||||
func srvObjMiddleware(h srvObjHandlerFunc) appsrv.FilterHandler {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
newCtx := NewContext(ctx, w, r)
|
||||
bmId := newCtx.Params()[PARAMS_BMID_KEY]
|
||||
srvId := newCtx.Params()[PARAMS_SRVID_KEY]
|
||||
baremetal := newCtx.GetBaremetalManager().GetBaremetalById(bmId)
|
||||
if baremetal == nil {
|
||||
newCtx.ResponseError(httperrors.NewNotFoundError("Not found baremetal by id: %s", bmId))
|
||||
return
|
||||
}
|
||||
if baremetal.GetServerId() != srvId {
|
||||
newCtx.ResponseError(httperrors.NewNotFoundError("Not found server by id: %s", srvId))
|
||||
return
|
||||
}
|
||||
srv := baremetal.GetServer()
|
||||
h(newCtx, baremetal, srv)
|
||||
}
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
context.Context
|
||||
userCred mcclient.TokenCredential
|
||||
params map[string]string
|
||||
query jsonutils.JSONObject
|
||||
data jsonutils.JSONObject
|
||||
request *http.Request
|
||||
writer http.ResponseWriter
|
||||
}
|
||||
|
||||
func NewContext(ctx context.Context, w http.ResponseWriter, r *http.Request) *Context {
|
||||
params, query, body := appsrv.FetchEnv(ctx, w, r)
|
||||
return &Context{
|
||||
Context: ctx,
|
||||
userCred: auth.FetchUserCredential(ctx, nil),
|
||||
params: params,
|
||||
query: query,
|
||||
data: body,
|
||||
request: r,
|
||||
writer: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *Context) Params() map[string]string {
|
||||
return ctx.params
|
||||
}
|
||||
|
||||
func (ctx *Context) Data() jsonutils.JSONObject {
|
||||
return ctx.data
|
||||
}
|
||||
|
||||
func (ctx *Context) Query() jsonutils.JSONObject {
|
||||
return ctx.query
|
||||
}
|
||||
|
||||
func (ctx *Context) UserCred() mcclient.TokenCredential {
|
||||
return ctx.userCred
|
||||
}
|
||||
|
||||
func (ctx *Context) TaskId() string {
|
||||
return ctx.Request().Header.Get(mcclient.TASK_ID)
|
||||
}
|
||||
|
||||
func (ctx *Context) ResponseStruct(obj interface{}) {
|
||||
appsrv.SendStruct(ctx.writer, obj)
|
||||
}
|
||||
|
||||
func (ctx *Context) ResponseJson(obj jsonutils.JSONObject) {
|
||||
appsrv.SendJSON(ctx.writer, obj)
|
||||
}
|
||||
|
||||
func (ctx *Context) ResponseError(err error) {
|
||||
httperrors.GeneralServerError(ctx.writer, err)
|
||||
}
|
||||
|
||||
func (ctx *Context) Request() *http.Request {
|
||||
return ctx.request
|
||||
}
|
||||
|
||||
func (ctx *Context) RequestRemoteIP() string {
|
||||
remoteAddr := ctx.Request().RemoteAddr
|
||||
return strings.Split(remoteAddr, ":")[0]
|
||||
}
|
||||
|
||||
func (ctx *Context) ResponseOk() {
|
||||
obj := jsonutils.NewDict()
|
||||
obj.Add(jsonutils.NewString("ok"), "result")
|
||||
appsrv.SendJSON(ctx.writer, obj)
|
||||
}
|
||||
|
||||
func (ctx *Context) GetBaremetalManager() *baremetal.SBaremetalManager {
|
||||
return baremetal.GetBaremetalManager()
|
||||
}
|
||||
|
||||
func (ctx *Context) DelayProcess(process ProcessFunc, data jsonutils.JSONObject) {
|
||||
DelayProcess(process, ctx.GetBaremetalManager().GetClientSession(), ctx.TaskId(), data)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,84 @@
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
)
|
||||
|
||||
func GetNicDHCPConfig(
|
||||
n *types.SNic,
|
||||
serverIP string,
|
||||
hostName string,
|
||||
isPxe bool,
|
||||
arch uint16,
|
||||
) (*dhcp.ResponseConfig, error) {
|
||||
if n == nil {
|
||||
return nil, fmt.Errorf("Nic is nil")
|
||||
}
|
||||
if n.IpAddr == "" {
|
||||
return nil, fmt.Errorf("Nic no ip address")
|
||||
}
|
||||
ipAddr, err := netutils.NewIPV4Addr(n.IpAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parse IP address error: %q", n.IpAddr)
|
||||
}
|
||||
|
||||
subnetMask := net.ParseIP(netutils.Masklen2Mask(n.MaskLen).String())
|
||||
|
||||
routes := make([][]string, 0)
|
||||
for _, route := range n.Routes {
|
||||
routes = append(routes, []string{route[0], route[1]})
|
||||
}
|
||||
|
||||
conf := &dhcp.ResponseConfig{
|
||||
ServerIP: net.ParseIP(serverIP),
|
||||
ClientIP: net.ParseIP(ipAddr.String()),
|
||||
Gateway: net.ParseIP(n.Gateway),
|
||||
SubnetMask: subnetMask,
|
||||
BroadcastAddr: net.ParseIP(ipAddr.BroadcastAddr(n.MaskLen).String()),
|
||||
DNSServer: net.ParseIP(n.Dns),
|
||||
Domain: n.Domain,
|
||||
OsName: "Linux",
|
||||
Hostname: hostName,
|
||||
Routes: routes,
|
||||
LeaseTime: time.Duration(o.Options.DhcpLeaseTime) * time.Second,
|
||||
RenewalTime: time.Duration(o.Options.DhcpRenewalTime) * time.Second,
|
||||
}
|
||||
|
||||
if isPxe {
|
||||
conf.BootServer = serverIP
|
||||
switch arch {
|
||||
case 7, 9:
|
||||
conf.BootFile = "bootx64.efi"
|
||||
case 6:
|
||||
conf.BootFile = "bootia32.efi"
|
||||
default:
|
||||
conf.BootFile = "pxelinux.0"
|
||||
}
|
||||
pxePath := filepath.Join(o.Options.TftpRoot, conf.BootFile)
|
||||
if f, err := os.Open(pxePath); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if info, err := f.Stat(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
pxeSize := info.Size()
|
||||
pxeBlk := pxeSize / 512
|
||||
if pxeSize > pxeBlk*512 {
|
||||
pxeBlk += 1
|
||||
}
|
||||
conf.BootBlock = uint16(pxeBlk)
|
||||
}
|
||||
}
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package options // import "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
@@ -0,0 +1,35 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon"
|
||||
)
|
||||
|
||||
type BaremetalOptions struct {
|
||||
cloudcommon.CommonOptions
|
||||
|
||||
ListenInterface string `help:"Master net interface of baremetal server" default:"br0"`
|
||||
AccessAddress string `help:"Management IP address of baremetal server, only need to use when multiple address bind to ListenInterface"`
|
||||
ListenAddress string `help:"PXE serve IP address to select when multiple address bind to ListenInterface" default:"0.0.0.0"`
|
||||
TftpRoot string `help:"tftp root directory"`
|
||||
AutoRegisterBaremetal bool `default:"true" help:"Automatically create a baremetal instance"`
|
||||
BaremetalsPath string `default:"/opt/cloud/workspace/baremetals" help:"Path for baremetals configuration files"`
|
||||
LinuxDefaultRootUser bool `default:"false" help:"Default account for linux system is root"`
|
||||
IpmiLanPortShared bool `default:"false" help:"IPMI Lan port shared or dedicated"`
|
||||
Zone string `help:"Zone where the agent locates"`
|
||||
DhcpLeaseTime int `default:"100663296" help:"DHCP lease time in seconds"` // 0x6000000
|
||||
DhcpRenewalTime int `default:"67108864" help:"DHCP renewal time in seconds"` // 0x4000000
|
||||
EnableGeneralGuestDhcp bool `default:"false" help:"Enable DHCP service for general guest, e.g. those on VMware ESXi or Xen"`
|
||||
ForceDhcpProbeIpmi bool `default:"false" help:"Force DHCP probe IPMI interface network connection"`
|
||||
TftpMaxTimeoutRetries int `default:"20" help:"Maximal tftp timeout retries, default is 20"`
|
||||
LengthyWorkerCount int `default:"8" help:"Parallel worker count for lengthy tasks"`
|
||||
ShortWorkerCount int `default:"8" help:"Parallel worker count for short-lived tasks"`
|
||||
|
||||
DefaultIpmiPassword string `help:"Default IPMI passowrd"`
|
||||
DefaultStrongIpmiPassword string `help:"Default strong IPMI passowrd"`
|
||||
|
||||
WindowsDefaultAdminUser bool `default:"true" help:"Default account for Windows system is Administrator"`
|
||||
}
|
||||
|
||||
var (
|
||||
Options BaremetalOptions
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
package profiles // import "yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
@@ -0,0 +1,108 @@
|
||||
package profiles
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
)
|
||||
|
||||
type IPMIProfile struct {
|
||||
LanChannel []int
|
||||
RootName string
|
||||
RootId int
|
||||
StrongPass bool
|
||||
}
|
||||
|
||||
func DefaultProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
}
|
||||
}
|
||||
|
||||
func InspurProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{8, 1},
|
||||
RootName: "admin",
|
||||
RootId: 2,
|
||||
}
|
||||
}
|
||||
|
||||
func LenovoProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{8},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
}
|
||||
}
|
||||
|
||||
func HpProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{2},
|
||||
RootName: "root",
|
||||
RootId: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func HuaweiProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
}
|
||||
}
|
||||
|
||||
func FoxconnProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
}
|
||||
}
|
||||
|
||||
func QemuProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{8, 1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
PROFILES map[string]IPMIProfile = map[string]IPMIProfile{
|
||||
"inspur": InspurProfile(),
|
||||
"lenovo": LenovoProfile(),
|
||||
"hp": HpProfile(),
|
||||
"huawei": HuaweiProfile(),
|
||||
"foxconn": FoxconnProfile(),
|
||||
"qemu": QemuProfile(),
|
||||
}
|
||||
)
|
||||
|
||||
func GetProfile(sysinfo *types.SIPMISystemInfo) IPMIProfile {
|
||||
profile, ok := PROFILES[strings.ToLower(sysinfo.Manufacture)]
|
||||
if ok {
|
||||
return profile
|
||||
}
|
||||
return DefaultProfile()
|
||||
}
|
||||
|
||||
func GetLanChannel(sysinfo *types.SIPMISystemInfo) []int {
|
||||
return GetProfile(sysinfo).LanChannel
|
||||
}
|
||||
|
||||
func GetRootId(sysinfo *types.SIPMISystemInfo) int {
|
||||
return GetProfile(sysinfo).RootId
|
||||
}
|
||||
|
||||
func GetRootName(sysinfo *types.SIPMISystemInfo) string {
|
||||
return GetProfile(sysinfo).RootName
|
||||
}
|
||||
|
||||
func IsStrongPass(sysinfo *types.SIPMISystemInfo) bool {
|
||||
return GetProfile(sysinfo).StrongPass
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package pxe
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
)
|
||||
|
||||
func (s *Server) serveDHCP(srv *dhcp.DHCPServer, handler dhcp.DHCPHandler) error {
|
||||
return srv.ListenAndServe(handler)
|
||||
}
|
||||
|
||||
type NetworkInterfaceIdent struct {
|
||||
Type uint16
|
||||
Major uint16
|
||||
Minior uint16
|
||||
}
|
||||
|
||||
type DHCPHandler struct {
|
||||
ClientMac net.HardwareAddr // client nic mac
|
||||
ClientAddr net.IP // IP address from DHCP client
|
||||
RelayAddr net.IP // IP address of DHCP relay agent
|
||||
Options dhcp.Options // dhcp packet options
|
||||
VendorClassId string
|
||||
ClientArch uint16
|
||||
NetworkInterfaceIdent NetworkInterfaceIdent
|
||||
ClientGuid string
|
||||
packet dhcp.Packet
|
||||
|
||||
// baremetal manager
|
||||
baremetalManager IBaremetalManager
|
||||
// baremetal instance
|
||||
baremetalInstance IBaremetalInstance
|
||||
// cloud network config
|
||||
netConfig *types.SNetworkConfig
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) ServeDHCP(pkt dhcp.Packet, _ *net.UDPAddr, _ *net.Interface) (dhcp.Packet, error) {
|
||||
//log.V(4).Debugf("[DHCP] request: %s", pkt.DebugString())
|
||||
err := h.parsePacket(pkt)
|
||||
if err != nil {
|
||||
log.Errorf("[DHCP] parse packet error: %v", err)
|
||||
}
|
||||
log.V(4).Debugf("[DHCP] parse packet end: %#v", h)
|
||||
|
||||
if h.RelayAddr.String() == "0.0.0.0" {
|
||||
return nil, fmt.Errorf("Request not from a DHCP relay, ignore mac: %s", h.ClientMac)
|
||||
}
|
||||
conf, err := h.fetchConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if conf == nil {
|
||||
return nil, fmt.Errorf("Empty packet config")
|
||||
}
|
||||
return dhcp.MakeReplyPacket(pkt, conf)
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) parsePacket(pkt dhcp.Packet) error {
|
||||
h.packet = pkt
|
||||
h.ClientAddr = pkt.CIAddr()
|
||||
h.ClientMac = pkt.CHAddr()
|
||||
h.RelayAddr = pkt.RelayAddr()
|
||||
h.Options = pkt.ParseOptions()
|
||||
|
||||
var (
|
||||
vendorClsId string
|
||||
cliArch uint16
|
||||
err error
|
||||
netIfIdent NetworkInterfaceIdent
|
||||
cliGuid string
|
||||
)
|
||||
|
||||
for optCode, data := range h.Options {
|
||||
switch optCode {
|
||||
case dhcp.OptionVendorClassIdentifier:
|
||||
vendorClsId, err = h.Options.String(optCode)
|
||||
case dhcp.OptionClientArchitecture:
|
||||
cliArch, err = h.Options.Uint16(optCode)
|
||||
case dhcp.OptionClientNetworkInterfaceIdentifier:
|
||||
netIfIdentBs, err := h.Options.Bytes(optCode)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
netIfIdent = NetworkInterfaceIdent{
|
||||
Type: uint16(netIfIdentBs[0]),
|
||||
Major: uint16(netIfIdentBs[1]),
|
||||
Minior: uint16(netIfIdentBs[2]),
|
||||
}
|
||||
log.Debugf("[DHCP] get network iface identifier: %#v", netIfIdent)
|
||||
case dhcp.OptionClientMachineIdentifier:
|
||||
switch len(data) {
|
||||
case 0:
|
||||
// A missing GUID is invalid according to the spec, however
|
||||
// there are PXE ROMs in the wild that omit the GUID and still
|
||||
// expect to boot.
|
||||
case 17:
|
||||
if data[0] != 0 {
|
||||
err = errors.New("malformed client GUID (option 97), leading byte must be zero")
|
||||
}
|
||||
default:
|
||||
err = errors.New("malformed client GUID (option 97), wrong size")
|
||||
}
|
||||
cliGuid, err = h.Options.String(optCode)
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("[DHCP] parse vendor option %d error: %v", optCode, err)
|
||||
}
|
||||
}
|
||||
h.VendorClassId = vendorClsId
|
||||
h.ClientArch = cliArch
|
||||
h.NetworkInterfaceIdent = netIfIdent
|
||||
h.ClientGuid = cliGuid
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) fetchConfig() (*dhcp.ResponseConfig, error) {
|
||||
// 1. find_network_conf
|
||||
netConf, err := h.findNetworkConf(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.netConfig = netConf
|
||||
|
||||
// TODO: set cache for netConf
|
||||
//
|
||||
if h.isPXERequest() {
|
||||
// handle PXE DHCP request
|
||||
log.Infof("DHCP relay from %s(%s) for %s, find matched networks: %#v", h.RelayAddr, h.ClientAddr, h.ClientMac, netConf)
|
||||
bmDesc, err := h.createOrUpdateBaremetal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = h.doInitBaremetalAdminNetif(bmDesc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.baremetalInstance.NeedPXEBoot() {
|
||||
return h.baremetalInstance.GetPXEDHCPConfig(h.ClientArch)
|
||||
}
|
||||
// ignore
|
||||
log.Warningf("No need to pxeboot, ignore the request ...(mac:%s guid:%s)", h.ClientMac, h.ClientGuid)
|
||||
return nil, nil
|
||||
} else {
|
||||
// handle normal DHCP request
|
||||
bmInstance := h.baremetalManager.GetBaremetalByMac(h.ClientMac)
|
||||
if bmInstance == nil {
|
||||
// options.EnableGeneralGuestDhcp
|
||||
// cloud be an instance not served by a host-server
|
||||
// from guestdhcp import GuestDHCPHelperTask
|
||||
// task = GuestDHCPHelperTask(self)
|
||||
// task.start()
|
||||
return nil, nil
|
||||
}
|
||||
h.baremetalInstance = bmInstance
|
||||
ipmiNic := h.baremetalInstance.GetIPMINic(h.ClientMac)
|
||||
if ipmiNic != nil && ipmiNic.Mac == h.ClientMac.String() {
|
||||
err = h.baremetalInstance.InitAdminNetif(h.ClientMac, h.netConfig, types.NIC_TYPE_IPMI, models.NETWORK_TYPE_IPMI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
err = h.baremetalInstance.RegisterNetif(h.ClientMac, h.netConfig)
|
||||
if err != nil {
|
||||
log.Errorf("RegisterNetif error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return h.baremetalInstance.GetDHCPConfig(h.ClientMac)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) findNetworkConf(filterUseIp bool) (*types.SNetworkConfig, error) {
|
||||
params := jsonutils.NewDict()
|
||||
if filterUseIp {
|
||||
params.Add(jsonutils.NewString(h.RelayAddr.String()), "ip")
|
||||
} else {
|
||||
params.Add(jsonutils.NewString(
|
||||
fmt.Sprintf("guest_gateway.equals(%s)", h.RelayAddr)),
|
||||
"filter.0")
|
||||
params.Add(jsonutils.NewString(
|
||||
fmt.Sprintf("guest_dhcp.equals(%s)", h.RelayAddr)),
|
||||
"filter.1")
|
||||
params.Add(jsonutils.JSONTrue, "filter_any")
|
||||
}
|
||||
params.Add(jsonutils.JSONTrue, "is_private")
|
||||
session := h.baremetalManager.GetClientSession()
|
||||
ret, err := modules.Networks.List(session, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ret.Data) == 0 {
|
||||
if !filterUseIp {
|
||||
// use ip filter try again
|
||||
return h.findNetworkConf(true)
|
||||
}
|
||||
return nil, fmt.Errorf("DHCP relay from %s(%s) for %s, find no match network", h.RelayAddr, h.ClientAddr, h.ClientMac)
|
||||
}
|
||||
|
||||
network := types.SNetworkConfig{}
|
||||
err = ret.Data[0].Unmarshal(&network)
|
||||
return &network, err
|
||||
}
|
||||
|
||||
// createOrUpdateBaremetal create or update baremetal by client MAC
|
||||
func (h *DHCPHandler) createOrUpdateBaremetal() (jsonutils.JSONObject, error) {
|
||||
session := h.baremetalManager.GetClientSession()
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(h.ClientMac.String()), "any_mac")
|
||||
ret, err := modules.Hosts.List(session, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch len(ret.Data) {
|
||||
case 0:
|
||||
// found new baremetal, create it if auto register
|
||||
if o.Options.AutoRegisterBaremetal {
|
||||
return h.createBaremetal()
|
||||
}
|
||||
case 1:
|
||||
// already exists, do update
|
||||
bmId, err := ret.Data[0].GetString("id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.updateBaremetal(bmId)
|
||||
}
|
||||
return nil, fmt.Errorf("Found %d records match %s", len(ret.Data), h.ClientMac)
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) createBaremetal() (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
mac := h.ClientMac.String()
|
||||
zoneId := h.baremetalManager.GetZoneId()
|
||||
name := fmt.Sprintf("BM%s", strings.Replace(mac, ":", "", -1))
|
||||
params.Add(jsonutils.NewString(name), "name")
|
||||
params.Add(jsonutils.NewString(mac), "access_mac")
|
||||
params.Add(jsonutils.NewString("baremetal"), "host_type")
|
||||
params.Add(jsonutils.JSONTrue, "is_baremetal")
|
||||
params.Add(jsonutils.NewString(zoneId), "zone_id")
|
||||
session := h.baremetalManager.GetClientSession()
|
||||
desc, err := modules.Hosts.Create(session, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) updateBaremetal(id string) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(h.ClientMac.String()), "access_mac")
|
||||
params.Add(jsonutils.NewString(h.baremetalManager.GetZoneId()), "zone_id")
|
||||
params.Add(jsonutils.NewString("baremetal"), "host_type")
|
||||
params.Add(jsonutils.JSONTrue, "is_baremetal")
|
||||
session := h.baremetalManager.GetClientSession()
|
||||
desc, err := modules.Hosts.Update(session, id, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) doInitBaremetalAdminNetif(desc jsonutils.JSONObject) error {
|
||||
var err error
|
||||
h.baremetalInstance, err = h.baremetalManager.AddBaremetal(desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = h.baremetalInstance.InitAdminNetif(h.ClientMac, h.netConfig, types.NIC_TYPE_ADMIN, models.NETWORK_TYPE_PXE)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) isPXERequest() bool {
|
||||
pkt := h.packet
|
||||
return dhcp.IsPXERequest(pkt)
|
||||
}
|
||||
|
||||
func (s *Server) validateDHCP(pkt dhcp.Packet) (Machine, Firmware, error) {
|
||||
var mach Machine
|
||||
var fwtype Firmware
|
||||
fwt, err := pkt.ParseOptions().Uint16(dhcp.OptionClientArchitecture)
|
||||
if err != nil {
|
||||
return mach, fwtype, fmt.Errorf("malformed DHCP option 93 (required for PXE): %s", err)
|
||||
}
|
||||
|
||||
// Basic architecture and firmware identification, based purely on
|
||||
// the PXE architecture option.
|
||||
switch fwt {
|
||||
// TODO: complete case 1, 2, 3, 4, 5, 8
|
||||
case 0:
|
||||
// Intel x86PC
|
||||
mach.Arch = ArchIA32
|
||||
fwtype = FirmwareX86PC
|
||||
case 1:
|
||||
// NEC/PC98
|
||||
mach.Arch = ArchUnknown
|
||||
fwtype = FirmwareUnknown
|
||||
case 2:
|
||||
// EFI Itanium
|
||||
mach.Arch = ArchUnknown
|
||||
fwtype = FirmwareUnknown
|
||||
case 3:
|
||||
// DEC Alpha
|
||||
mach.Arch = ArchUnknown
|
||||
fwtype = FirmwareUnknown
|
||||
case 4:
|
||||
// Arc x86
|
||||
mach.Arch = ArchUnknown
|
||||
fwtype = FirmwareUnknown
|
||||
case 5:
|
||||
// Intel Lean Client
|
||||
mach.Arch = ArchUnknown
|
||||
fwtype = FirmwareUnknown
|
||||
case 6:
|
||||
// EFI IA32
|
||||
mach.Arch = ArchIA32
|
||||
fwtype = FirmwareEFI32
|
||||
case 7:
|
||||
// EFI BC
|
||||
mach.Arch = ArchX64
|
||||
fwtype = FirmwareEFI64
|
||||
case 8:
|
||||
// EFI Xscale
|
||||
mach.Arch = ArchUnknown
|
||||
fwtype = FirmwareUnknown
|
||||
case 9:
|
||||
// EFI x86-64
|
||||
mach.Arch = ArchX64
|
||||
fwtype = FirmwareEFIBC
|
||||
default:
|
||||
return mach, 0, fmt.Errorf("unsupported client firmware type '%d'", fwtype)
|
||||
}
|
||||
|
||||
guid, _ := pkt.ParseOptions().Bytes(dhcp.OptionClientMachineIdentifier)
|
||||
switch len(guid) {
|
||||
case 0:
|
||||
// A missing GUID is invalid according to the spec, however
|
||||
// there are PXE ROMs in the wild that omit the GUID and still
|
||||
// expect to boot. The only thing we do with the GUID is
|
||||
// mirror it back to the client if it's there, so we might as
|
||||
// well accept these buggy ROMs.
|
||||
case 17:
|
||||
if guid[0] != 0 {
|
||||
return mach, 0, errors.New("malformed client GUID (option 97), leading byte must be zero")
|
||||
}
|
||||
default:
|
||||
return mach, 0, errors.New("malformed client GUID (option 97), wrong size")
|
||||
}
|
||||
|
||||
mach.MAC = pkt.CHAddr()
|
||||
return mach, fwtype, nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package pxe // import "yunion.io/x/onecloud/pkg/baremetal/pxe"
|
||||
@@ -0,0 +1,134 @@
|
||||
package pxe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
)
|
||||
|
||||
const (
|
||||
portDHCP = 67
|
||||
portTFTP = 69
|
||||
)
|
||||
|
||||
// Architecture describes a kind of CPU architecture
|
||||
type Architecture int
|
||||
|
||||
// Architecture types that pxe knows how to boot
|
||||
// These architectures are self-reported by the booting machine. The
|
||||
// machine may support additional execution mode. For example, legacy
|
||||
// PC BIOS reports itself as an ArchIA32, but may also support ArchX64
|
||||
// execution
|
||||
const (
|
||||
// ArchIA32 is a 32-bit x86 machine. It may also support X64
|
||||
// execution, but pxe has no way of kowning.
|
||||
ArchIA32 Architecture = iota
|
||||
// ArchX64 is a 64-bit x86 machine (aka amd64 aka x64)
|
||||
ArchX64
|
||||
ArchUnknown
|
||||
)
|
||||
|
||||
func (a Architecture) String() string {
|
||||
switch a {
|
||||
case ArchIA32:
|
||||
return "IA32"
|
||||
case ArchX64:
|
||||
return "X64"
|
||||
default:
|
||||
return "Unknown architecture"
|
||||
}
|
||||
}
|
||||
|
||||
// A Machine describes a machine that is attempting to boot
|
||||
type Machine struct {
|
||||
MAC net.HardwareAddr
|
||||
Arch Architecture
|
||||
}
|
||||
|
||||
// Firmware describes a kind of firmware attempting to boot.
|
||||
// This should only be used for selecting the right bootloader within
|
||||
// pxe, kernel selection should key off the more generic
|
||||
// Architecture
|
||||
type Firmware int
|
||||
|
||||
// The bootloaders that pxe knows how to handle
|
||||
const (
|
||||
FirmwareX86PC Firmware = iota // "Classic" x86 BIOS with PXE/UNDI support
|
||||
FirmwareEFI32 // 32-bit x86 processor running EFI
|
||||
FirmwareEFI64 // 64-bit x86 processor running EFI
|
||||
FirmwareEFIBC // 64-bit x86 processor running EFI
|
||||
FirmwareX86Ipxe // "Classic" x86 BIOS running iPXE (no UNDI support)
|
||||
FirmwareUnknown
|
||||
)
|
||||
|
||||
type IBaremetalManager interface {
|
||||
GetZoneId() string
|
||||
GetBaremetalByMac(mac net.HardwareAddr) IBaremetalInstance
|
||||
AddBaremetal(desc jsonutils.JSONObject) (IBaremetalInstance, error)
|
||||
GetClientSession() *mcclient.ClientSession
|
||||
}
|
||||
|
||||
type IBaremetalInstance interface {
|
||||
NeedPXEBoot() bool
|
||||
GetIPMINic(cliMac net.HardwareAddr) *types.SNic
|
||||
GetPXEDHCPConfig(arch uint16) (*dhcp.ResponseConfig, error)
|
||||
GetDHCPConfig(cliMac net.HardwareAddr) (*dhcp.ResponseConfig, error)
|
||||
InitAdminNetif(cliMac net.HardwareAddr, netConf *types.SNetworkConfig, nicType string, netType string) error
|
||||
RegisterNetif(cliMac net.HardwareAddr, netConf *types.SNetworkConfig) error
|
||||
GetTFTPResponse() string
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
// Address to listen on, or empty for all interfaces
|
||||
Address string
|
||||
DHCPPort int
|
||||
TFTPPort int
|
||||
TFTPRootDir string
|
||||
errs chan error
|
||||
BaremetalManager IBaremetalManager
|
||||
}
|
||||
|
||||
func (s *Server) Serve() error {
|
||||
if s.Address == "" {
|
||||
s.Address = "0.0.0.0"
|
||||
}
|
||||
if s.DHCPPort == 0 {
|
||||
s.DHCPPort = portDHCP
|
||||
}
|
||||
if s.TFTPPort == 0 {
|
||||
s.TFTPPort = portTFTP
|
||||
}
|
||||
|
||||
tftpConn, err := net.ListenPacket("udp", fmt.Sprintf("%s:%d", s.Address, s.TFTPPort))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tftpHandler, err := NewTFTPHandler(s.TFTPRootDir, s.BaremetalManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//tftpSrv := tftp.NewServer(tftpHandler.ReadHandler, nil)
|
||||
//tftpSrv.SetTimeout(5 * time.Second)
|
||||
|
||||
log.Infof("DHCPServer Bind %s %d", s.Address, s.DHCPPort)
|
||||
dhcpSrv, _, err := dhcp.NewDHCPServer2(s.Address, s.DHCPPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.errs = make(chan error)
|
||||
|
||||
dhcpHandler := &DHCPHandler{baremetalManager: s.BaremetalManager}
|
||||
|
||||
go func() { s.errs <- s.serveDHCP(dhcpSrv, dhcpHandler) }()
|
||||
go func() { s.errs <- s.serveTFTP(tftpConn, tftpHandler) }()
|
||||
|
||||
err = <-s.errs
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package pxe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/tftp"
|
||||
)
|
||||
|
||||
var (
|
||||
PxeLinuxCfgPattern = `^pxelinux.cfg/01-(?P<mac>([0-9a-f]{2}-){5}[0-9a-f]{2})$`
|
||||
)
|
||||
|
||||
type TFTPHandler struct {
|
||||
RootDir string
|
||||
BaremetalManager IBaremetalManager
|
||||
}
|
||||
|
||||
func NewTFTPHandler(rootDir string, baremetalManager IBaremetalManager) (*TFTPHandler, error) {
|
||||
if _, err := os.Stat(rootDir); err != nil {
|
||||
return nil, fmt.Errorf("TFTP root dir %q stat error: %v", rootDir, err)
|
||||
}
|
||||
return &TFTPHandler{
|
||||
RootDir: rootDir,
|
||||
BaremetalManager: baremetalManager,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Handle is called when client starts file download from server
|
||||
func (h *TFTPHandler) Handle(filename string, clientAddr net.Addr) (io.ReadCloser, int64, error) {
|
||||
regEx := regexp.MustCompile(PxeLinuxCfgPattern)
|
||||
matches := regEx.FindStringSubmatch(filename)
|
||||
|
||||
if len(matches) != 0 {
|
||||
paramsMap := make(map[string]string)
|
||||
// pxelinux config matched
|
||||
for i, name := range regEx.SubexpNames() {
|
||||
if i > 0 && i <= len(matches) {
|
||||
paramsMap[name] = matches[i]
|
||||
}
|
||||
}
|
||||
mac, ok := paramsMap["mac"]
|
||||
if !ok {
|
||||
return nil, 0, fmt.Errorf("request filename %q not found mac pattern", filename)
|
||||
}
|
||||
macAddr, err := net.ParseMAC(mac)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("Parse mac string %q error: %v", mac, err)
|
||||
}
|
||||
return h.sendPxeLinuxCfgResponse(macAddr, clientAddr)
|
||||
}
|
||||
return h.sendFile(filename, clientAddr)
|
||||
}
|
||||
|
||||
func (h *TFTPHandler) sendPxeLinuxCfgResponse(mac net.HardwareAddr, _ net.Addr) (io.ReadCloser, int64, error) {
|
||||
log.Debugf("[TFTP] client mac: %s", mac)
|
||||
bmInstance := h.BaremetalManager.GetBaremetalByMac(mac)
|
||||
if bmInstance == nil {
|
||||
err := fmt.Errorf("Not found baremetal instance by mac: %s", mac)
|
||||
log.Errorf("Get baremetal error: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
respStr := bmInstance.GetTFTPResponse()
|
||||
log.Debugf("[TFTP] get tftp response config: %s", respStr)
|
||||
bs := []byte(respStr)
|
||||
size := int64(len(bs))
|
||||
buffer := bytes.NewBufferString(respStr)
|
||||
|
||||
return ioutil.NopCloser(buffer), size, nil
|
||||
}
|
||||
|
||||
func (h *TFTPHandler) sendFile(filename string, _ net.Addr) (io.ReadCloser, int64, error) {
|
||||
filename = h.getFilePath(filename)
|
||||
|
||||
st, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
log.Errorf("TFTP stat file %q error: %v", filename, err)
|
||||
return nil, 0, err
|
||||
}
|
||||
if !st.Mode().IsRegular() {
|
||||
return nil, 0, fmt.Errorf("requested path %q is not a file", filename)
|
||||
}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
log.Errorf("TFTP open file %q error: %v", filename, err)
|
||||
return nil, 0, err
|
||||
}
|
||||
return file, st.Size(), err
|
||||
}
|
||||
|
||||
func (h *TFTPHandler) getFilePath(fileName string) string {
|
||||
return filepath.Join(h.RootDir, fileName)
|
||||
}
|
||||
|
||||
func (h *TFTPHandler) transferLog(clientAddr net.Addr, path string, err error) {
|
||||
log.Debugf("TFTP transfer log clientAddr: %s, path: %s, error: %v", clientAddr, path, err)
|
||||
}
|
||||
|
||||
func (s *Server) serveTFTP(l net.PacketConn, handler *TFTPHandler) error {
|
||||
ts := tftp.Server{
|
||||
Handler: handler.Handle,
|
||||
InfoLog: func(msg string) { log.Debugf("TFTP msg: %s", msg) },
|
||||
TransferLog: handler.transferLog,
|
||||
}
|
||||
err := ts.Serve(l)
|
||||
if err != nil {
|
||||
return fmt.Errorf("TFTP server shut down: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package service // import "yunion.io/x/onecloud/pkg/baremetal/service"
|
||||
@@ -0,0 +1,41 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/handler"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/tasks"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/service"
|
||||
)
|
||||
|
||||
type BaremetalService struct {
|
||||
service.SServiceBase
|
||||
}
|
||||
|
||||
func New() *BaremetalService {
|
||||
return &BaremetalService{}
|
||||
}
|
||||
|
||||
func (s *BaremetalService) StartService() {
|
||||
cloudcommon.ParseOptions(&o.Options, os.Args, "baremetal.conf", "baremetal")
|
||||
cloudcommon.InitAuth(&o.Options.CommonOptions, s.startAgent)
|
||||
|
||||
app := cloudcommon.InitApp(&o.Options.CommonOptions, false)
|
||||
handler.InitHandlers(app)
|
||||
|
||||
cloudcommon.ServeForeverWithCleanup(app, &o.Options.CommonOptions, func() {
|
||||
tasks.OnStop()
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BaremetalService) startAgent() {
|
||||
err := baremetal.Start()
|
||||
if err != nil {
|
||||
log.Fatalf("Start agent error: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package baremetal
|
||||
|
||||
const (
|
||||
INIT = "init"
|
||||
PREPARE = "prepare"
|
||||
PREPARE_FAIL = "prepare_fail"
|
||||
READY = "ready"
|
||||
RUNNING = "running"
|
||||
MAINTAINING = "maintaining"
|
||||
START_MAINTAIN = "start_maintain"
|
||||
DELETING = "deleting"
|
||||
DELETE = "delete"
|
||||
DELETE_FAIL = "delete_fail"
|
||||
UNKNOWN = "unknown"
|
||||
SYNCING_STATUS = "syncing_status"
|
||||
SYNC = "sync"
|
||||
SYNC_FAIL = "sync_fail"
|
||||
START_CONVERT = "start_convert"
|
||||
CONVERTING = "converting"
|
||||
START_FAIL = "start_fail"
|
||||
STOP_FAIL = "stop_fail"
|
||||
)
|
||||
|
||||
const (
|
||||
NIC_TYPE_IPMI = "ipmi"
|
||||
NIC_TYPE_ADMIN = "admin"
|
||||
)
|
||||
|
||||
var NIC_TYPES = []string{NIC_TYPE_ADMIN, NIC_TYPE_IPMI}
|
||||
@@ -0,0 +1,29 @@
|
||||
package status
|
||||
|
||||
const (
|
||||
INIT = "init"
|
||||
PREPARE = "prepare"
|
||||
PREPARE_FAIL = "prepare_fail"
|
||||
READY = "ready"
|
||||
RUNNING = "running"
|
||||
MAINTAINING = "maintaining"
|
||||
START_MAINTAIN = "start_maintain"
|
||||
DELETING = "deleting"
|
||||
DELETE = "delete"
|
||||
DELETE_FAIL = "delete_fail"
|
||||
UNKNOWN = "unknown"
|
||||
SYNCING_STATUS = "syncing_status"
|
||||
SYNC = "sync"
|
||||
SYNC_FAIL = "sync_fail"
|
||||
START_CONVERT = "start_convert"
|
||||
CONVERTING = "converting"
|
||||
START_FAIL = "start_fail"
|
||||
STOP_FAIL = "stop_fail"
|
||||
)
|
||||
|
||||
const (
|
||||
SERVER_RUNNING = "running"
|
||||
SERVER_ADMIN = "admin"
|
||||
SERVER_READY = "ready"
|
||||
SERVER_UNKNOWN = "unknown"
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
package status // import "yunion.io/x/onecloud/pkg/baremetal/status"
|
||||
@@ -0,0 +1,405 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type Queue struct {
|
||||
objList *list.List
|
||||
objListLock *sync.Mutex
|
||||
}
|
||||
|
||||
func NewQueue() *Queue {
|
||||
return &Queue{
|
||||
objList: list.New(),
|
||||
objListLock: new(sync.Mutex),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queue) Append(obj interface{}) *Queue {
|
||||
q.objListLock.Lock()
|
||||
defer q.objListLock.Unlock()
|
||||
q.objList.PushBack(obj)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *Queue) First() interface{} {
|
||||
q.objListLock.Lock()
|
||||
defer q.objListLock.Unlock()
|
||||
if q.objList.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return q.objList.Front().Value
|
||||
}
|
||||
|
||||
func (q *Queue) IsEmpty() bool {
|
||||
return q.First() == nil
|
||||
}
|
||||
|
||||
func (q *Queue) Pop() interface{} {
|
||||
q.objListLock.Lock()
|
||||
defer q.objListLock.Unlock()
|
||||
if q.objList.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
first := q.objList.Front()
|
||||
q.objList.Remove(first)
|
||||
return first.Value
|
||||
}
|
||||
|
||||
func (q *Queue) String() string {
|
||||
itemStrings := debugString(q.objList.Front())
|
||||
return fmt.Sprintf("%v", itemStrings)
|
||||
}
|
||||
|
||||
func debugString(elem *list.Element) []string {
|
||||
if elem == nil {
|
||||
return nil
|
||||
}
|
||||
strings := []string{fmt.Sprintf("%v", elem.Value)}
|
||||
rest := debugString(elem.Next())
|
||||
if rest != nil {
|
||||
strings = append(strings, rest...)
|
||||
}
|
||||
return strings
|
||||
}
|
||||
|
||||
type TaskQueue struct {
|
||||
*Queue
|
||||
}
|
||||
|
||||
type TaskStageFunc func(ctx context.Context, args interface{}) error
|
||||
|
||||
type SSHTaskStageFunc func(ctx context.Context, cli *ssh.Client, args interface{}) error
|
||||
|
||||
type sshStageWrapper struct {
|
||||
sshStage SSHTaskStageFunc
|
||||
remoteIP string
|
||||
password string
|
||||
}
|
||||
|
||||
func sshStageW(
|
||||
stage SSHTaskStageFunc,
|
||||
remoteIP string,
|
||||
password string,
|
||||
) *sshStageWrapper {
|
||||
return &sshStageWrapper{
|
||||
sshStage: stage,
|
||||
remoteIP: remoteIP,
|
||||
password: password,
|
||||
}
|
||||
}
|
||||
|
||||
func (sw *sshStageWrapper) Do(ctx context.Context, args interface{}) error {
|
||||
cli, err := ssh.NewClient(sw.remoteIP, 22, "root", sw.password, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sw.sshStage(ctx, cli, args)
|
||||
}
|
||||
|
||||
type ITask interface {
|
||||
// GetStage return current task stage func
|
||||
GetStage() TaskStageFunc
|
||||
// SetStage set task next execute stage func
|
||||
SetStage(stage TaskStageFunc)
|
||||
|
||||
// GetSSHStage return current task ssh stage func
|
||||
GetSSHStage() SSHTaskStageFunc
|
||||
// SetSSHStage set task next execute ssh stage func
|
||||
SetSSHStage(stage SSHTaskStageFunc)
|
||||
|
||||
// GetTaskId return remote service task id
|
||||
GetTaskId() string
|
||||
GetClientSession() *mcclient.ClientSession
|
||||
|
||||
GetTaskQueue() *TaskQueue
|
||||
// GetData return TaskData from region
|
||||
GetData() jsonutils.JSONObject
|
||||
GetName() string
|
||||
|
||||
Execute(ITask ITask, args interface{})
|
||||
SetSSHStageParams(task ITask, remoteIP string, passwd string)
|
||||
SSHExecute(task ITask, remoteIP string, passwd string, args interface{})
|
||||
NeedPXEBoot() bool
|
||||
}
|
||||
|
||||
func NewTaskQueue() *TaskQueue {
|
||||
return &TaskQueue{
|
||||
Queue: NewQueue(),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *TaskQueue) GetTask() ITask {
|
||||
if q.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
return q.First().(ITask)
|
||||
}
|
||||
|
||||
func (q *TaskQueue) PopTask() ITask {
|
||||
if q.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
return q.Pop().(ITask)
|
||||
}
|
||||
|
||||
func (q *TaskQueue) AppendTask(task ITask) *TaskQueue {
|
||||
log.Infof("Append task %s", task.GetName())
|
||||
q.Append(task)
|
||||
return q
|
||||
}
|
||||
|
||||
type TaskFactory func(bm IBaremetal, taskId string, data jsonutils.JSONObject) (ITask, error)
|
||||
|
||||
type SBaremetalTaskBase struct {
|
||||
Baremetal IBaremetal
|
||||
userCred mcclient.TokenCredential
|
||||
stageFunc TaskStageFunc
|
||||
sshStageFunc SSHTaskStageFunc
|
||||
taskId string
|
||||
data jsonutils.JSONObject
|
||||
}
|
||||
|
||||
func newBaremetalTaskBase(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) *SBaremetalTaskBase {
|
||||
task := &SBaremetalTaskBase{
|
||||
Baremetal: baremetal,
|
||||
taskId: taskId,
|
||||
data: data,
|
||||
}
|
||||
return task
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetTaskQueue() *TaskQueue {
|
||||
return task.Baremetal.GetTaskQueue()
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetTaskId() string {
|
||||
return task.taskId
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetData() jsonutils.JSONObject {
|
||||
return task.data
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetStage() TaskStageFunc {
|
||||
return task.stageFunc
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetSSHStage() SSHTaskStageFunc {
|
||||
return task.sshStageFunc
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) SetStage(stage TaskStageFunc) {
|
||||
task.stageFunc = stage
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) SetSSHStage(stage SSHTaskStageFunc) {
|
||||
task.sshStageFunc = stage
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) Execute(iTask ITask, args interface{}) {
|
||||
ExecuteTask(iTask, args)
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) SetSSHStageParams(iTask ITask, remoteIP string, password string) {
|
||||
iTask.SetStage(sshStageW(iTask.GetSSHStage(), remoteIP, password).Do)
|
||||
}
|
||||
|
||||
func (task *SBaremetalTaskBase) SSHExecute(
|
||||
iTask ITask,
|
||||
remoteIP string,
|
||||
password string,
|
||||
args interface{},
|
||||
) {
|
||||
//iTask.SetStage(sshStageW(iTask.GetSSHStage(), remoteIP, password).Do)
|
||||
task.SetSSHStageParams(iTask, remoteIP, password)
|
||||
ExecuteTask(iTask, args)
|
||||
}
|
||||
|
||||
//func (task *SBaremetalTaskBase) CallNextStage(iTask ITask, stage TaskStageFunc, args interface{}) {
|
||||
//iTask.SetStage(stage)
|
||||
//ExecuteTask(iTask, args)
|
||||
//}
|
||||
|
||||
func (task *SBaremetalTaskBase) GetClientSession() *mcclient.ClientSession {
|
||||
return task.Baremetal.GetClientSession()
|
||||
}
|
||||
|
||||
func (self *SBaremetalTaskBase) EnsurePowerShutdown(soft bool) error {
|
||||
log.Infof("EnsurePowerShutdown: soft=%v", soft)
|
||||
status, err := self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
startTime := time.Now()
|
||||
maxWait := 60 * time.Second
|
||||
for status == "" || status == types.POWER_STATUS_ON {
|
||||
if time.Since(startTime).Seconds() >= maxWait.Seconds() && soft {
|
||||
soft = false
|
||||
}
|
||||
err = self.Baremetal.DoPowerShutdown(soft)
|
||||
if err != nil {
|
||||
log.Errorf("DoPowerShutdown: %v", err)
|
||||
}
|
||||
time.Sleep(20 * time.Second)
|
||||
status, err = self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
log.Errorf("GetPowerStatus: %v", err)
|
||||
}
|
||||
}
|
||||
if status != types.POWER_STATUS_OFF {
|
||||
return fmt.Errorf("Baremetal invalid status %s for shutdown", status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalTaskBase) EnsurePowerUp(bootdev string) error {
|
||||
log.Infof("EnsurePowerUp: bootdev=%s", bootdev)
|
||||
var bootFunc func() error = nil
|
||||
switch bootdev {
|
||||
case "pxe":
|
||||
bootFunc = self.Baremetal.DoPXEBoot
|
||||
case "disk":
|
||||
bootFunc = self.Baremetal.DoDiskBoot
|
||||
}
|
||||
if bootFunc == nil {
|
||||
return fmt.Errorf("No boot func %s found", bootdev)
|
||||
}
|
||||
status, err := self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for status == "" || status == types.POWER_STATUS_OFF {
|
||||
if status == types.POWER_STATUS_OFF {
|
||||
err = bootFunc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
status, err = self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status == "" || status == types.POWER_STATUS_OFF {
|
||||
time.Sleep(40 * time.Second)
|
||||
status, err = self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if status != types.POWER_STATUS_ON {
|
||||
return fmt.Errorf("Baremetal invalid restart status: %s", status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalTaskBase) NeedPXEBoot() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type IPXEBootTask interface {
|
||||
ITask
|
||||
OnPXEBoot(ctx context.Context, cli *ssh.Client, args interface{}) error
|
||||
}
|
||||
|
||||
type SBaremetalPXEBootTaskBase struct {
|
||||
*SBaremetalTaskBase
|
||||
pxeBootTask IPXEBootTask
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
func newBaremetalPXEBootTaskBase(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) *SBaremetalPXEBootTaskBase {
|
||||
baseTask := newBaremetalTaskBase(baremetal, taskId, data)
|
||||
self := &SBaremetalPXEBootTaskBase{
|
||||
SBaremetalTaskBase: baseTask,
|
||||
}
|
||||
return self
|
||||
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) InitPXEBootTask(pxeBootTask IPXEBootTask, data jsonutils.JSONObject) (*SBaremetalPXEBootTaskBase, error) {
|
||||
self.pxeBootTask = pxeBootTask
|
||||
//OnInitStage(pxeBootTask)
|
||||
sshConf, _ := self.Baremetal.GetSSHConfig()
|
||||
if sshConf != nil && self.Baremetal.TestSSHConfig() {
|
||||
pxeBootTask.SetSSHStage(pxeBootTask.OnPXEBoot)
|
||||
pxeBootTask.SetSSHStageParams(pxeBootTask, sshConf.RemoteIP, sshConf.Password)
|
||||
return self, nil
|
||||
}
|
||||
// Do soft reboot
|
||||
if data != nil && jsonutils.QueryBoolean(data, "soft_boot", false) {
|
||||
self.startTime = time.Now()
|
||||
if err := self.Baremetal.DoPowerShutdown(true); err != nil {
|
||||
log.Errorf("DoPowerShutdown error: %v", err)
|
||||
}
|
||||
//self.CallNextStage(self, self.WaitForShutdown, nil)
|
||||
self.SetStage(self.WaitForShutdown)
|
||||
|
||||
return self, nil
|
||||
}
|
||||
// shutdown and power up to PXE mode
|
||||
if err := self.EnsurePowerShutdown(false); err != nil {
|
||||
return self, fmt.Errorf("EnsurePowerShutdown: %v", err)
|
||||
}
|
||||
if err := self.EnsurePowerUp("pxe"); err != nil {
|
||||
return self, fmt.Errorf("EnsurePowerUp to pxe: %v", err)
|
||||
}
|
||||
// this stage will be called by baremetalInstance when pxe start notify
|
||||
self.SetSSHStage(pxeBootTask.OnPXEBoot)
|
||||
return self, nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) NeedPXEBoot() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) WaitForShutdown(ctx context.Context, args interface{}) error {
|
||||
self.SetStage(self.OnStopComplete)
|
||||
status, err := self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status == types.POWER_STATUS_OFF {
|
||||
self.Execute(self, nil)
|
||||
} else if time.Since(self.startTime) >= 90*time.Second {
|
||||
err = self.Baremetal.DoPowerShutdown(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) OnStopComplete(ctx context.Context, args interface{}) error {
|
||||
err := self.EnsurePowerUp("pxe")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.SetSSHStage(self.pxeBootTask.OnPXEBoot)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalPXEBootTaskBase) GetName() string {
|
||||
return "BaremetalPXEBootTaskBase"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQueue(t *testing.T) {
|
||||
type test struct {
|
||||
queue *Queue
|
||||
expected string
|
||||
}
|
||||
q123 := NewQueue().Append("1").Append("2").Append("3")
|
||||
q123Pop := NewQueue().Append("1").Append("2").Append("3")
|
||||
q123Pop.Pop()
|
||||
qEmptyPop := NewQueue().Append("1").Append("2")
|
||||
qEmptyPop.Pop()
|
||||
qEmptyPop.Pop()
|
||||
qEmptyPop.Pop()
|
||||
tests := map[string]test{
|
||||
"Empty queue": {
|
||||
queue: NewQueue(),
|
||||
expected: "[]",
|
||||
},
|
||||
"Queue append": {
|
||||
queue: q123,
|
||||
expected: "[1 2 3]",
|
||||
},
|
||||
"Queue pop": {
|
||||
queue: q123Pop,
|
||||
expected: "[2 3]",
|
||||
},
|
||||
"Queue pop to empty": {
|
||||
queue: qEmptyPop,
|
||||
expected: "[]",
|
||||
},
|
||||
}
|
||||
for name, testCase := range tests {
|
||||
output := testCase.queue.String()
|
||||
expected := testCase.expected
|
||||
if output != expected {
|
||||
t.Errorf("TestCase %q failed, output: %v, expected: %v", name, output, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type IServerBaseDeployTask interface {
|
||||
IPXEBootTask
|
||||
DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error)
|
||||
}
|
||||
|
||||
type SBaremetalServerBaseDeployTask struct {
|
||||
*SBaremetalPXEBootTaskBase
|
||||
serverDeployTask IServerBaseDeployTask
|
||||
}
|
||||
|
||||
func newBaremetalServerBaseDeployTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
deployTask IServerBaseDeployTask,
|
||||
) (*SBaremetalServerBaseDeployTask, error) {
|
||||
task := new(SBaremetalServerBaseDeployTask)
|
||||
baseTask := newBaremetalPXEBootTaskBase(baremetal, taskId, data)
|
||||
task.SBaremetalPXEBootTaskBase = baseTask
|
||||
_, err := baseTask.InitPXEBootTask(task, data)
|
||||
task.serverDeployTask = deployTask
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerBaseDeployTask) GetName() string {
|
||||
return "BaremetalServerBaseDeployTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerBaseDeployTask) GetFinishAction() string {
|
||||
if self.data != nil {
|
||||
action, _ := self.data.GetString("on_finish")
|
||||
return action
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
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)
|
||||
result, err := self.serverDeployTask.DoDeploys(term)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = term.Run(
|
||||
"/bin/sync",
|
||||
"/sbin/sysctl -w vm.drop_caches=3",
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
onFinishAction := self.GetFinishAction()
|
||||
if utils.IsInStringArray(onFinishAction, []string{"restart", "shutdown"}) {
|
||||
err = self.EnsurePowerShutdown(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if onFinishAction == "restart" {
|
||||
err = self.EnsurePowerUp("disk")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
self.Baremetal.AutoSyncAllStatus()
|
||||
SetTaskComplete(self, result)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,529 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/seclib"
|
||||
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/detect_storages"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
"yunion.io/x/onecloud/pkg/util/sysutils"
|
||||
)
|
||||
|
||||
type sBaremetalPrepareTask struct {
|
||||
baremetal IBaremetal
|
||||
}
|
||||
|
||||
func newBaremetalPrepareTask(baremetal IBaremetal) *sBaremetalPrepareTask {
|
||||
return &sBaremetalPrepareTask{
|
||||
baremetal: baremetal,
|
||||
}
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
|
||||
_, err := cli.Run("/lib/mos/sysinit.sh")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sysInfo, err := getDMISysinfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cpuInfo, err := getCPUInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dmiCPUInfo, err := getDMICPUInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
memInfo, err := getDMIMemInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nicsInfo, err := getNicsInfo(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
raidDiskInfo, nonRaidDiskInfo, pcieDiskInfo, err := detect_storages.DetectStorageInfo(cli, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
diskInfo := make([]*baremetal.BaremetalStorage, 0)
|
||||
diskInfo = append(diskInfo, raidDiskInfo...)
|
||||
diskInfo = append(diskInfo, nonRaidDiskInfo...)
|
||||
diskInfo = append(diskInfo, pcieDiskInfo...)
|
||||
var storageDriver string
|
||||
if len(raidDiskInfo) > 0 {
|
||||
raidDrivers := []string{}
|
||||
for _, drv := range raidDiskInfo {
|
||||
raidDrivers = append(raidDrivers, drv.Driver)
|
||||
}
|
||||
storageDriver = strings.Join(raidDrivers, ",")
|
||||
} else {
|
||||
storageDriver = baremetal.DISK_DRIVER_LINUX
|
||||
}
|
||||
|
||||
ipmiEnable, err := isIPMIEnable(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ipmiInfo := &types.SIPMIInfo{
|
||||
Present: ipmiEnable,
|
||||
}
|
||||
// set ipmi nic DHCP
|
||||
if ipmiEnable {
|
||||
sshIPMI := ipmitool.NewSSHIPMI(cli)
|
||||
// ipmitool.SetSysInfo
|
||||
ipmiSysInfo := sysInfo.ToIPMISystemInfo()
|
||||
SetIPMILanPortShared(sshIPMI, ipmiSysInfo)
|
||||
ipmiUser, ipmiPasswd, ipmiIpAddr := task.getIPMIUserPasswd(ipmiSysInfo)
|
||||
ipmiInfo.Username = ipmiUser
|
||||
ipmiInfo.Password = ipmiPasswd
|
||||
|
||||
var ipmiLanChannel int = -1
|
||||
for _, lanChannel := range ipmitool.GetLanChannels(ipmiSysInfo) {
|
||||
log.Infof("Try lan channel %d ...", lanChannel)
|
||||
conf, err := ipmitool.GetLanConfig(sshIPMI, lanChannel)
|
||||
if err != nil {
|
||||
log.Errorf("Get lan channel %d config error: %v", lanChannel, err)
|
||||
continue
|
||||
}
|
||||
if conf.Mac == nil {
|
||||
log.Errorf("Lan channel %d MAC address is empty", lanChannel)
|
||||
continue
|
||||
}
|
||||
ipmiNic := &types.SNicDevInfo{
|
||||
Mac: conf.Mac,
|
||||
Up: false,
|
||||
Speed: 100,
|
||||
Mtu: 1500,
|
||||
}
|
||||
task.sendNicInfo(ipmiNic, -1, types.NIC_TYPE_IPMI, true, "")
|
||||
rootId := ipmitool.GetRootId(ipmiSysInfo)
|
||||
err = ipmitool.SetLanUserPasswd(sshIPMI, lanChannel, rootId, ipmiUser, ipmiPasswd)
|
||||
if err != nil {
|
||||
log.Errorf("Lan channel %d set user password error: %v", lanChannel, err)
|
||||
}
|
||||
err = ipmitool.EnableLanAccess(sshIPMI, lanChannel)
|
||||
if err != nil {
|
||||
log.Errorf("Lan channel %d enable lan access error: %v", lanChannel, err)
|
||||
}
|
||||
|
||||
tryAddrs := make([]string, 0)
|
||||
if ipmiIpAddr != "" {
|
||||
tryAddrs = append(tryAddrs, ipmiIpAddr)
|
||||
}
|
||||
if conf.IPAddr != "" && conf.IPAddr != ipmiIpAddr {
|
||||
tryAddrs = append(tryAddrs, conf.IPAddr)
|
||||
}
|
||||
if len(tryAddrs) > 0 && !o.Options.ForceDhcpProbeIpmi {
|
||||
for _, tryAddr := range tryAddrs {
|
||||
log.Infof("IP addr found in IPMI config, try use %s as IPMI address", tryAddr)
|
||||
ipConf, err := task.getIPMIIPConfig(tryAddr)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get IPMI ipconfig for %s", tryAddr)
|
||||
continue
|
||||
}
|
||||
err = ipmitool.SetLanStatic(sshIPMI, lanChannel, ipConf.IPAddr, ipConf.Netmask, ipConf.Gateway)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to set IPMI static net config %#v for %s", *ipConf, tryAddr)
|
||||
continue
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
conf, err = ipmitool.GetLanConfig(sshIPMI, lanChannel)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get lan config after set static network: %v", err)
|
||||
continue
|
||||
}
|
||||
log.Infof("Get lan config %#v", *conf)
|
||||
if conf.IPAddr == "" || conf.IPAddr != tryAddr {
|
||||
log.Errorf("Failed to set ipmi lan channel %d static ipaddr", lanChannel)
|
||||
continue
|
||||
}
|
||||
rmcpIPMI := ipmitool.NewLanPlusIPMI(tryAddr, ipmiUser, ipmiPasswd)
|
||||
conf2, err := ipmitool.GetLanConfig(rmcpIPMI, lanChannel)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get lan channel %d config use RMCP mode: %v", lanChannel, err)
|
||||
continue
|
||||
}
|
||||
if len(conf2.Mac) != 0 &&
|
||||
conf2.Mac.String() == conf.Mac.String() &&
|
||||
conf2.IPAddr != "" && conf2.IPAddr == tryAddr {
|
||||
// make sure the ipaddr is a IPMI address
|
||||
// enable the netif
|
||||
if err := task.sendNicInfo(ipmiNic, -1, types.NIC_TYPE_IPMI, false, tryAddr); err != nil {
|
||||
log.Errorf("Fail to set existing BMC IP address to %s", tryAddr)
|
||||
} else {
|
||||
ipmiInfo.IpAddr = tryAddr
|
||||
ipmiLanChannel = lanChannel
|
||||
break
|
||||
}
|
||||
} else {
|
||||
log.Errorf("Use RMCP mode get invalid lan config: %#v", conf2)
|
||||
}
|
||||
if ipmiLanChannel >= 0 {
|
||||
// found and set config on lanChannel
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(tryAddrs) > 0 {
|
||||
task.baremetal.SetExistingIPMIIPAddr(tryAddrs[0])
|
||||
}
|
||||
|
||||
err = ipmitool.SetLanDHCP(sshIPMI, lanChannel)
|
||||
if err != nil {
|
||||
log.Errorf("Set lan channel %d dhcp error: %v", lanChannel, err)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
nic := task.baremetal.GetIPMINic(conf.Mac)
|
||||
maxTries := 180 // wait 3 minutes
|
||||
for tried := 0; nic != nil && nic.IpAddr == "" && tried < maxTries; tried++ {
|
||||
nic = task.baremetal.GetIPMINic(conf.Mac)
|
||||
}
|
||||
if len(nic.IpAddr) == 0 {
|
||||
err = ipmitool.DoBMCReset(sshIPMI) // do BMC reset to force DHCP request
|
||||
if err != nil {
|
||||
log.Errorf("Do BMC reset error: %v", err)
|
||||
}
|
||||
}
|
||||
for tried := 0; nic != nil && nic.IpAddr == "" && tried < maxTries; tried++ {
|
||||
nic = task.baremetal.GetIPMINic(conf.Mac)
|
||||
}
|
||||
if nic != nil && len(nic.IpAddr) == 0 {
|
||||
log.Errorf("DHCP wait IPMI address fail, retry ...")
|
||||
continue
|
||||
}
|
||||
log.Infof("DHCP get IPMI address succ, wait 2 seconds ...")
|
||||
var tried int = 0
|
||||
for tried < maxTries {
|
||||
time.Sleep(2 * time.Second)
|
||||
lanConf, err := ipmitool.GetLanConfig(sshIPMI, lanChannel)
|
||||
if err != nil {
|
||||
log.Errorf("Get lan config at channel %d error: %v", lanChannel, err)
|
||||
tried += 2
|
||||
continue
|
||||
}
|
||||
if lanConf.IPAddr == nic.IpAddr {
|
||||
break
|
||||
}
|
||||
log.Infof("waiting IPMI DHCP address %s %s", lanConf.IPAddr, nic.IpAddr)
|
||||
tried += 2
|
||||
}
|
||||
if tried >= maxTries {
|
||||
continue
|
||||
}
|
||||
err = ipmitool.SetLanStatic(
|
||||
sshIPMI,
|
||||
lanChannel,
|
||||
nic.IpAddr,
|
||||
nic.GetNetMask(),
|
||||
nic.Gateway,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("Set lanChannel %d static net %#v error: %v", lanChannel, nic, err)
|
||||
continue
|
||||
}
|
||||
ipmiInfo.IpAddr = nic.IpAddr
|
||||
ipmiLanChannel = lanChannel
|
||||
}
|
||||
if ipmiLanChannel == -1 {
|
||||
return fmt.Errorf("Fail to get IPMI address from DHCP")
|
||||
}
|
||||
ipmiInfo.LanChannel = ipmiLanChannel
|
||||
}
|
||||
|
||||
adminNic := task.baremetal.GetAdminNic()
|
||||
|
||||
// collect params
|
||||
updateInfo := make(map[string]interface{})
|
||||
oname := fmt.Sprintf("BM%s", strings.Replace(adminNic.Mac, ":", "", -1))
|
||||
if task.baremetal.GetName() == oname {
|
||||
updateInfo["name"] = fmt.Sprintf("BM-%s", strings.Replace(ipmiInfo.IpAddr, ".", "-", -1))
|
||||
}
|
||||
updateInfo["access_ip"] = adminNic.IpAddr
|
||||
updateInfo["cpu_count"] = cpuInfo.Count
|
||||
updateInfo["node_count"] = dmiCPUInfo.Nodes
|
||||
updateInfo["cpu_desc"] = cpuInfo.Model
|
||||
updateInfo["cpu_mhz"] = cpuInfo.Freq
|
||||
updateInfo["cpu_cache"] = cpuInfo.Cache
|
||||
updateInfo["mem_size"] = memInfo.Total
|
||||
updateInfo["storage_driver"] = storageDriver
|
||||
updateInfo["storage_info"] = diskInfo
|
||||
updateInfo["sys_info"] = sysInfo
|
||||
updateInfo["sn"] = sysInfo.SN
|
||||
size, diskType := task.collectDiskInfo(diskInfo)
|
||||
updateInfo["storage_size"] = size
|
||||
updateInfo["storage_type"] = diskType
|
||||
updateData := jsonutils.Marshal(updateInfo)
|
||||
updateData.(*jsonutils.JSONDict).Update(ipmiInfo.ToPrepareParams())
|
||||
_, err = modules.Hosts.Update(task.getClientSession(), task.baremetal.GetId(), updateData)
|
||||
if err != nil {
|
||||
log.Errorf("Update baremetal info error: %v", err)
|
||||
}
|
||||
if err := task.sendStorageInfo(size); err != nil {
|
||||
log.Errorf("sendStorageInfo error: %v", err)
|
||||
}
|
||||
for i := range nicsInfo {
|
||||
if nicsInfo[i].Mac.String() == adminNic.GetMac().String() {
|
||||
if i != 0 {
|
||||
nicsInfo = append(nicsInfo[i:], nicsInfo[0:i]...)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
err = task.removeAllNics()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range nicsInfo {
|
||||
err = task.sendNicInfo(nicsInfo[i], i, "", false, "")
|
||||
if err != nil {
|
||||
log.Errorf("Send nicinfo idx: %d, %#v error: %v", i, nicsInfo[i], err)
|
||||
}
|
||||
}
|
||||
for _, nicInfo := range nicsInfo {
|
||||
if nicInfo.Mac.String() != adminNic.GetMac().String() && nicInfo.Up {
|
||||
err = task.doNicWireProbe(cli, nicInfo)
|
||||
if err != nil {
|
||||
log.Errorf("doNicWireProbe nic %#v error: %v", nicInfo, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Prepare complete")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) getIPMIUserPasswd(sysInfo *types.SIPMISystemInfo) (string, string, string) {
|
||||
var (
|
||||
ipmiUser string
|
||||
ipmiPasswd string
|
||||
ipmiIpAddr string
|
||||
)
|
||||
ipmiUser = profiles.GetRootName(sysInfo)
|
||||
isStrongPass := profiles.IsStrongPass(sysInfo)
|
||||
if !isStrongPass && o.Options.DefaultIpmiPassword != "" {
|
||||
ipmiPasswd = o.Options.DefaultIpmiPassword
|
||||
} else if isStrongPass && o.Options.DefaultStrongIpmiPassword != "" {
|
||||
ipmiPasswd = o.Options.DefaultStrongIpmiPassword
|
||||
} else if isStrongPass && o.Options.DefaultIpmiPassword != "" {
|
||||
ipmiPasswd = o.Options.DefaultIpmiPassword
|
||||
} else {
|
||||
ipmiPasswd = seclib.RandomPassword(20)
|
||||
}
|
||||
oldIPMIConf := task.baremetal.GetRawIPMIConfig()
|
||||
if oldIPMIConf != nil {
|
||||
if oldIPMIConf.Username != "" {
|
||||
ipmiUser = oldIPMIConf.Username
|
||||
}
|
||||
if oldIPMIConf.Password != "" {
|
||||
ipmiPasswd = oldIPMIConf.Password
|
||||
}
|
||||
if oldIPMIConf.IpAddr != "" {
|
||||
ipmiIpAddr = oldIPMIConf.IpAddr
|
||||
}
|
||||
}
|
||||
return ipmiUser, ipmiPasswd, ipmiIpAddr
|
||||
}
|
||||
|
||||
type ipmiIPConfig struct {
|
||||
IPAddr string
|
||||
Netmask string
|
||||
Gateway string
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) getIPMIIPConfig(ipAddr string) (*ipmiIPConfig, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(ipAddr), "ip")
|
||||
listRet, err := modules.Networks.List(task.getClientSession(), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(listRet.Data) != 1 {
|
||||
return nil, fmt.Errorf("Invalid network list count: %d", len(listRet.Data))
|
||||
}
|
||||
netObj := listRet.Data[0]
|
||||
config := &ipmiIPConfig{}
|
||||
config.IPAddr = ipAddr
|
||||
maskLen, _ := netObj.Int("guest_ip_mask")
|
||||
config.Netmask = netutils.Masklen2Mask(int8(maskLen)).String()
|
||||
config.Gateway, _ = netObj.GetString("guest_gateway")
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) getClientSession() *mcclient.ClientSession {
|
||||
return task.baremetal.GetClientSession()
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) removeAllNics() error {
|
||||
resp, err := modules.Hosts.PerformAction(
|
||||
task.getClientSession(),
|
||||
task.baremetal.GetId(),
|
||||
"remove-all-netifs",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return task.baremetal.SaveDesc(resp)
|
||||
}
|
||||
|
||||
func getDMISysinfo(cli *ssh.Client) (*types.SDMISystemInfo, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseDMISysinfo(ret)
|
||||
}
|
||||
|
||||
func getCPUInfo(cli *ssh.Client) (*types.SCPUInfo, error) {
|
||||
ret, err := cli.Run("cat /proc/cpuinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseCPUInfo(ret)
|
||||
}
|
||||
|
||||
func getDMICPUInfo(cli *ssh.Client) (*types.SDMICPUInfo, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 4")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseDMICPUInfo(ret), nil
|
||||
}
|
||||
|
||||
func getDMIMemInfo(cli *ssh.Client) (*types.SDMIMemInfo, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 17")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sysutils.ParseDMIMemInfo(ret), nil
|
||||
}
|
||||
|
||||
func getNicsInfo(cli *ssh.Client) ([]*types.SNicDevInfo, error) {
|
||||
ret, err := cli.Run("/lib/mos/lsnic")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to retrieve NIC info: %v", err)
|
||||
}
|
||||
return sysutils.ParseNicInfo(ret), nil
|
||||
}
|
||||
|
||||
func isIPMIEnable(cli *ssh.Client) (bool, error) {
|
||||
ret, err := cli.Run("/usr/sbin/dmidecode -t 38")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to retrieve IPMI info: %v", err)
|
||||
}
|
||||
return sysutils.ParseDMIIPMIInfo(ret), nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) sendNicInfo(nic *types.SNicDevInfo, idx int, nicType string, reset bool, ipAddr string) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(nic.Mac.String()), "mac")
|
||||
params.Add(jsonutils.NewInt(int64(nic.Speed)), "rate")
|
||||
if idx >= 0 {
|
||||
params.Add(jsonutils.NewInt(int64(idx)), "index")
|
||||
}
|
||||
if nicType != "" {
|
||||
params.Add(jsonutils.NewString(nicType), "nic_type")
|
||||
}
|
||||
params.Add(jsonutils.NewInt(int64(nic.Mtu)), "mtu")
|
||||
params.Add(jsonutils.NewBool(nic.Up), "link_up")
|
||||
if reset {
|
||||
params.Add(jsonutils.JSONTrue, "reset")
|
||||
}
|
||||
if ipAddr != "" {
|
||||
params.Add(jsonutils.NewString(ipAddr), "ip_addr")
|
||||
params.Add(jsonutils.JSONTrue, "require_designated_ip")
|
||||
}
|
||||
resp, err := modules.Hosts.PerformAction(
|
||||
task.getClientSession(),
|
||||
task.baremetal.GetId(),
|
||||
"add-netif",
|
||||
params,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task.baremetal.SaveDesc(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) sendStorageInfo(size int64) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewInt(size), "capacity")
|
||||
params.Add(jsonutils.NewString(task.baremetal.GetZoneId()), "zone_id")
|
||||
_, err := modules.Hosts.PerformAction(task.getClientSession(), task.baremetal.GetId(), "update-storage", params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) doNicWireProbe(cli *ssh.Client, nic *types.SNicDevInfo) error {
|
||||
maxTries := 6
|
||||
for tried := 0; tried < maxTries; tried++ {
|
||||
log.Infof("doNicWireProbe %v", nic)
|
||||
_, err := cli.Run(fmt.Sprintf("/sbin/udhcpc -t 1 -T 3 -n -i %s", nic.Dev))
|
||||
if err != nil {
|
||||
log.Errorf("/sbin/udhcpc error: %v", err)
|
||||
}
|
||||
nicInfo := task.baremetal.GetNicByMac(nic.Mac)
|
||||
if nicInfo != nil && nicInfo.WireId != "" {
|
||||
log.Infof("doNicWireProbe success, get result %#v", nicInfo)
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) collectDiskInfo(diskInfo []*baremetal.BaremetalStorage) (int64, string) {
|
||||
cnt := 0
|
||||
rotateCnt := 0
|
||||
var size int64 = 0
|
||||
var diskType string
|
||||
for _, d := range diskInfo {
|
||||
if d.Rotate {
|
||||
rotateCnt += 1
|
||||
}
|
||||
size += d.Size
|
||||
cnt += 1
|
||||
}
|
||||
if rotateCnt == cnt {
|
||||
diskType = "rotate"
|
||||
} else if rotateCnt == 0 {
|
||||
diskType = "ssd"
|
||||
} else {
|
||||
diskType = "hybrid"
|
||||
}
|
||||
return size, diskType
|
||||
}
|
||||
|
||||
func SetIPMILanPortShared(cli ipmitool.IPMIExecutor, sysInfo *types.SIPMISystemInfo) {
|
||||
if !o.Options.IpmiLanPortShared {
|
||||
return
|
||||
}
|
||||
oemName := strings.ToLower(sysInfo.Manufacture)
|
||||
var err error
|
||||
if strings.Contains(oemName, "huawei") {
|
||||
err = ipmitool.SetHuaweiIPMILanPortShared(cli)
|
||||
} else if strings.Contains(oemName, "dell") {
|
||||
err = ipmitool.SetDellIPMILanPortShared(cli)
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("Set %s ipmi lan port shared failed: %v", oemName, err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalServerCreateTask struct {
|
||||
*SBaremetalServerBaseDeployTask
|
||||
}
|
||||
|
||||
func NewBaremetalServerCreateTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalServerCreateTask)
|
||||
baseTask, err := newBaremetalServerBaseDeployTask(baremetal, taskId, data, task)
|
||||
task.SBaremetalServerBaseDeployTask = baseTask
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerCreateTask) GetName() string {
|
||||
return "BaremetalServerCreateTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerCreateTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
// Build raid
|
||||
err := self.Baremetal.GetServer().DoDiskConfig(term)
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
if err := self.Baremetal.GetServer().DoEraseDisk(term); err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
parts, err := self.Baremetal.GetServer().DoPartitionDisk(term)
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
}
|
||||
data := jsonutils.NewDict()
|
||||
disks, err := self.Baremetal.GetServer().SyncPartitionSize(term, parts)
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
}
|
||||
data.Add(jsonutils.Marshal(disks), "disks")
|
||||
deployInfo, err := self.Baremetal.GetServer().DoDeploy(term, self.data, true)
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
}
|
||||
if deployInfo != nil {
|
||||
data.Update(deployInfo)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerCreateTask) onError(term *ssh.Client, err error) error {
|
||||
if err1 := self.Baremetal.GetServer().DoEraseDisk(term); err1 != nil {
|
||||
log.Warningf("EraseDisk error: %v", err1)
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalServerDeployTask struct {
|
||||
*SBaremetalServerBaseDeployTask
|
||||
}
|
||||
|
||||
func NewBaremetalServerDeployTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalServerDeployTask)
|
||||
baseTask, err := newBaremetalServerBaseDeployTask(baremetal, taskId, data, task)
|
||||
task.SBaremetalServerBaseDeployTask = baseTask
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerDeployTask) GetName() string {
|
||||
return "BaremetalServerDeployTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerDeployTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
return self.Baremetal.GetServer().DoDeploy(term, self.data, false)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalServerDestroyTask struct {
|
||||
*SBaremetalServerBaseDeployTask
|
||||
}
|
||||
|
||||
func NewBaremetalServerDestroyTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalServerDestroyTask)
|
||||
baseTask, err := newBaremetalServerBaseDeployTask(baremetal, taskId, data, task)
|
||||
task.SBaremetalServerBaseDeployTask = baseTask
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerDestroyTask) GetName() string {
|
||||
return "BaremetalServerDestroyTask"
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if err := self.Baremetal.GetServer().DoDiskUnconfig(term); err != nil {
|
||||
log.Errorf("Baremetal do disk unconfig: %v", err)
|
||||
}
|
||||
self.Baremetal.RemoveServer()
|
||||
return nil, nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package tasks // import "yunion.io/x/onecloud/pkg/baremetal/tasks"
|
||||
@@ -0,0 +1,40 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
baremetaltypes "yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
type IBaremetal interface {
|
||||
GetId() string
|
||||
GetZoneId() string
|
||||
GetTaskQueue() *TaskQueue
|
||||
GetSSHConfig() (*types.SSHConfig, error)
|
||||
TestSSHConfig() bool
|
||||
GetAdminNic() *types.SNic
|
||||
GetName() string
|
||||
GetClientSession() *mcclient.ClientSession
|
||||
SaveDesc(desc jsonutils.JSONObject) error
|
||||
GetNicByMac(net.HardwareAddr) *types.SNic
|
||||
GetRawIPMIConfig() *types.SIPMIInfo
|
||||
GetIPMINic(mac net.HardwareAddr) *types.SNic
|
||||
SetExistingIPMIIPAddr(ipAddr string)
|
||||
GetServer() baremetaltypes.IBaremetalServer
|
||||
|
||||
SyncStatus(status, reason string)
|
||||
AutoSyncStatus()
|
||||
SyncAllStatus(status string)
|
||||
AutoSyncAllStatus()
|
||||
|
||||
GetPowerStatus() (string, error)
|
||||
DoPowerShutdown(soft bool) error
|
||||
DoPXEBoot() error
|
||||
DoDiskBoot() error
|
||||
|
||||
RemoveServer()
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalMaintenanceTask struct {
|
||||
*SBaremetalPXEBootTaskBase
|
||||
}
|
||||
|
||||
func NewBaremetalMaintenanceTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalMaintenanceTask)
|
||||
baseTask := newBaremetalPXEBootTaskBase(baremetal, taskId, data)
|
||||
task.SBaremetalPXEBootTaskBase = baseTask
|
||||
_, err := baseTask.InitPXEBootTask(task, data)
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalMaintenanceTask) OnPXEBoot(ctx context.Context, term *ssh.Client, args interface{}) error {
|
||||
sshConfig := term.GetConfig()
|
||||
dataObj := map[string]interface{}{
|
||||
"username": sshConfig.Username,
|
||||
"password": sshConfig.Password,
|
||||
"ip": sshConfig.Host,
|
||||
}
|
||||
if jsonutils.QueryBoolean(self.data, "guest_running", false) {
|
||||
dataObj["guest_running"] = true
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
SetTaskComplete(self, jsonutils.Marshal(dataObj))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/status"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalServerPrepareTask struct {
|
||||
*SBaremetalTaskBase
|
||||
}
|
||||
|
||||
func NewBaremetalServerPrepareTask(
|
||||
baremetal IBaremetal,
|
||||
) *SBaremetalServerPrepareTask {
|
||||
baseTask := newBaremetalTaskBase(baremetal, "", nil)
|
||||
task := &SBaremetalServerPrepareTask{
|
||||
SBaremetalTaskBase: baseTask,
|
||||
}
|
||||
task.SetSSHStage(task.OnPXEBootRequest)
|
||||
return task
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerPrepareTask) NeedPXEBoot() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerPrepareTask) GetName() string {
|
||||
return "BaremetalServerPrepareTask"
|
||||
}
|
||||
|
||||
// OnPXEBootRequest called by notify api handler
|
||||
func (self *SBaremetalServerPrepareTask) OnPXEBootRequest(ctx context.Context, cli *ssh.Client, args interface{}) error {
|
||||
err := newBaremetalPrepareTask(self.Baremetal).DoPrepare(cli)
|
||||
if err != nil {
|
||||
log.Errorf("Prepare failed: %v", err)
|
||||
self.Baremetal.SyncStatus(status.PREPARE_FAIL, err.Error())
|
||||
return err
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalServerRebuildTask struct {
|
||||
*SBaremetalServerBaseDeployTask
|
||||
}
|
||||
|
||||
func NewBaremetalServerRebuildTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalServerRebuildTask)
|
||||
baseTask, err := newBaremetalServerBaseDeployTask(baremetal, taskId, data, task)
|
||||
task.SBaremetalServerBaseDeployTask = baseTask
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerRebuildTask) GetName() string {
|
||||
return "BaremetalServerRebuildTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerRebuildTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
parts, err := self.Baremetal.GetServer().DoRebuildRootDisk(term)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Rebuild root disk: %v", err)
|
||||
}
|
||||
disks, err := self.Baremetal.GetServer().SyncPartitionSize(term, parts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SyncPartitionSize: %v", err)
|
||||
}
|
||||
data := jsonutils.NewDict()
|
||||
data.Add(jsonutils.NewArray(disks...), "disks")
|
||||
deployInfo, err := self.Baremetal.GetServer().DoDeploy(term, data, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DoDeploy: %v", err)
|
||||
}
|
||||
data.Update(deployInfo)
|
||||
return data, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalReprepareTask struct {
|
||||
*SBaremetalServerBaseDeployTask
|
||||
}
|
||||
|
||||
func NewBaremetalReprepareTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalReprepareTask)
|
||||
baseTask, err := newBaremetalServerBaseDeployTask(baremetal, taskId, data, task)
|
||||
task.SBaremetalServerBaseDeployTask = baseTask
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalReprepareTask) GetName() string {
|
||||
return "BaremetalReprepareTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalReprepareTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
task := newBaremetalPrepareTask(self.Baremetal)
|
||||
err := task.DoPrepare(term)
|
||||
return nil, err
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type SBaremetalResetBMCTask struct {
|
||||
*SBaremetalPXEBootTaskBase
|
||||
term *ssh.Client
|
||||
}
|
||||
|
||||
func NewBaremetalResetBMCTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalResetBMCTask)
|
||||
baseTask := newBaremetalPXEBootTaskBase(baremetal, taskId, data)
|
||||
task.SBaremetalPXEBootTaskBase = baseTask
|
||||
_, err := baseTask.InitPXEBootTask(task, data)
|
||||
return task, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalResetBMCTask) GetName() string {
|
||||
return "BaremetalResetBMCTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalResetBMCTask) GetIPMITool() *ipmitool.SSHIPMI {
|
||||
return ipmitool.NewSSHIPMI(self.term)
|
||||
}
|
||||
|
||||
func (self *SBaremetalResetBMCTask) OnPXEBoot(ctx context.Context, term *ssh.Client, args interface{}) error {
|
||||
self.term = term
|
||||
self.SetStage(self.WaitForBMCReady)
|
||||
err := ipmitool.DoBMCReset(self.GetIPMITool())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(10 * time.Second)
|
||||
ExecuteTask(self, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalResetBMCTask) WaitForBMCReady(ctx context.Context, args interface{}) error {
|
||||
self.SetStage(self.OnBMCReady)
|
||||
status, err := ipmitool.GetChassisPowerStatus(self.GetIPMITool())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status != "" && status == types.POWER_STATUS_ON {
|
||||
ExecuteTask(self, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalResetBMCTask) OnBMCReady(ctx context.Context, args interface{}) error {
|
||||
time.Sleep(20 * time.Second)
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
)
|
||||
|
||||
type SBaremetalServerStartTask struct {
|
||||
*SBaremetalTaskBase
|
||||
}
|
||||
|
||||
func NewBaremetalServerStartTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
baseTask := newBaremetalTaskBase(baremetal, taskId, data)
|
||||
self := &SBaremetalServerStartTask{
|
||||
SBaremetalTaskBase: baseTask,
|
||||
}
|
||||
if err := self.Baremetal.DoDiskBoot(); err != nil {
|
||||
return nil, fmt.Errorf("DoDiskBoot: %v", err)
|
||||
}
|
||||
self.SetStage(self.WaitForStart)
|
||||
ExecuteTask(self, nil)
|
||||
return self, nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerStartTask) GetName() string {
|
||||
return "BaremetalServerStartTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerStartTask) WaitForStart(ctx context.Context, args interface{}) error {
|
||||
self.SetStage(self.OnStartComplete)
|
||||
status, err := self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetPowerStatus: %v", err)
|
||||
}
|
||||
log.Infof("%s WaitForStart status=%s", self.GetName(), status)
|
||||
if status == types.POWER_STATUS_ON {
|
||||
ExecuteTask(self, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerStartTask) OnStartComplete(ctx context.Context, args interface{}) error {
|
||||
self.Baremetal.SyncAllStatus(types.POWER_STATUS_ON)
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
)
|
||||
|
||||
type SBaremetalServerStopTask struct {
|
||||
*SBaremetalTaskBase
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
func NewBaremetalServerStopTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
baseTask := newBaremetalTaskBase(baremetal, taskId, data)
|
||||
self := &SBaremetalServerStopTask{
|
||||
SBaremetalTaskBase: baseTask,
|
||||
}
|
||||
if err := self.Baremetal.DoPowerShutdown(true); err != nil {
|
||||
return nil, fmt.Errorf("Do power shutdown error: %v", err)
|
||||
}
|
||||
self.startTime = time.Now()
|
||||
self.SetStage(self.WaitForStop)
|
||||
ExecuteTask(self, nil)
|
||||
return self, nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerStopTask) GetName() string {
|
||||
return "BaremetalServerStopTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerStopTask) WaitForStop(ctx context.Context, args interface{}) error {
|
||||
self.SetStage(self.OnStopComplete)
|
||||
status, err := self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetPowerStatus: %v", err)
|
||||
}
|
||||
if status == types.POWER_STATUS_OFF {
|
||||
ExecuteTask(self, nil)
|
||||
} else if time.Since(self.startTime) >= 90*time.Second {
|
||||
if err := self.Baremetal.DoPowerShutdown(false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerStopTask) OnStopComplete(ctx context.Context, args interface{}) error {
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
baremetalstatus "yunion.io/x/onecloud/pkg/baremetal/status"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
)
|
||||
|
||||
type SBaremetalUnmaintenanceTask struct {
|
||||
*SBaremetalTaskBase
|
||||
}
|
||||
|
||||
func NewBaremetalUnmaintenanceTask(
|
||||
baremetal IBaremetal,
|
||||
taskId string,
|
||||
data jsonutils.JSONObject,
|
||||
) (ITask, error) {
|
||||
task := new(SBaremetalUnmaintenanceTask)
|
||||
baseTask := newBaremetalTaskBase(baremetal, taskId, data)
|
||||
task.SBaremetalTaskBase = baseTask
|
||||
var err error
|
||||
if jsonutils.QueryBoolean(task.data, "guest_running", false) {
|
||||
err = task.EnsurePowerShutdown(false)
|
||||
if err != nil {
|
||||
return task, fmt.Errorf("EnsurePowerShutdown hard: %v", err)
|
||||
}
|
||||
err = task.EnsurePowerUp("disk")
|
||||
if err != nil {
|
||||
return task, fmt.Errorf("EnsurePowerUp disk: %v", err)
|
||||
}
|
||||
task.Baremetal.SyncStatus(baremetalstatus.RUNNING, "")
|
||||
SetTaskComplete(task, nil)
|
||||
return task, nil
|
||||
}
|
||||
task.SetStage(task.WaitForStop)
|
||||
err = task.EnsurePowerShutdown(true)
|
||||
if err != nil {
|
||||
return task, fmt.Errorf("EnsurePowerShutdown soft: %v", err)
|
||||
}
|
||||
ExecuteTask(task, nil)
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalUnmaintenanceTask) WaitForStop(ctx context.Context, args interface{}) error {
|
||||
status, err := self.Baremetal.GetPowerStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.SetStage(self.OnStopComplete)
|
||||
if status == types.POWER_STATUS_OFF {
|
||||
ExecuteTask(self, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalUnmaintenanceTask) OnStopComplete(ctx context.Context, args interface{}) error {
|
||||
self.Baremetal.SyncStatus(baremetalstatus.READY, "")
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalUnmaintenanceTask) GetName() string {
|
||||
return "BaremetalUnmaintenanceTask"
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
)
|
||||
|
||||
var baremetalTaskWorkerMan *appsrv.SWorkerManager
|
||||
|
||||
func init() {
|
||||
baremetalTaskWorkerMan = appsrv.NewWorkerManager("BaremetalTaskWorkerManager", 8, 1024, false)
|
||||
}
|
||||
|
||||
func GetWorkManager() *appsrv.SWorkerManager {
|
||||
return baremetalTaskWorkerMan
|
||||
}
|
||||
|
||||
func OnStop() {
|
||||
for GetWorkManager().ActiveWorkerCount() > 0 {
|
||||
log.Warningf("Busy workers count %d, waiting them finish", GetWorkManager().ActiveWorkerCount())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func ExecuteTask(task ITask, args interface{}) {
|
||||
baremetalTaskWorkerMan.Run(func() {
|
||||
executeTask(task, args)
|
||||
}, nil, nil)
|
||||
}
|
||||
|
||||
func executeTask(task ITask, args interface{}) {
|
||||
if task == nil {
|
||||
return
|
||||
}
|
||||
curStage := task.GetStage()
|
||||
if curStage == nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Errorf("Execute task panic: %v", err)
|
||||
debug.PrintStack()
|
||||
SetTaskFail(task, fmt.Errorf("%v", err))
|
||||
}
|
||||
}()
|
||||
err := curStage(context.Background(), args)
|
||||
if err != nil {
|
||||
log.Errorf("Execute task %s error: %v", task.GetName(), err)
|
||||
SetTaskFail(task, err)
|
||||
}
|
||||
}
|
||||
|
||||
func SetTaskComplete(task ITask, data jsonutils.JSONObject) {
|
||||
taskId := task.GetTaskId()
|
||||
if taskId != "" {
|
||||
session := task.GetClientSession()
|
||||
modules.ComputeTasks.TaskComplete(session, taskId, data)
|
||||
}
|
||||
onTaskEnd(task)
|
||||
}
|
||||
|
||||
func SetTaskFail(task ITask, err error) {
|
||||
taskId := task.GetTaskId()
|
||||
if taskId != "" {
|
||||
session := task.GetClientSession()
|
||||
modules.ComputeTasks.TaskFailed(session, taskId, err)
|
||||
}
|
||||
onTaskEnd(task)
|
||||
}
|
||||
|
||||
func onTaskEnd(task ITask) {
|
||||
task.SetStage(nil)
|
||||
ExecuteTask(task.GetTaskQueue().PopTask(), nil)
|
||||
}
|
||||
|
||||
func OnInitStage(task ITask) error {
|
||||
log.Infof("Start task %s", task.GetName())
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package types // import "yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
@@ -0,0 +1,26 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/disktool"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type IBaremetalServer interface {
|
||||
GetName() string
|
||||
GetId() string
|
||||
RemoveDesc()
|
||||
DoDiskUnconfig(term *ssh.Client) error
|
||||
DoDiskConfig(term *ssh.Client) error
|
||||
DoEraseDisk(term *ssh.Client) error
|
||||
DoPartitionDisk(term *ssh.Client) ([]*disktool.Partition, error)
|
||||
DoRebuildRootDisk(term *ssh.Client) ([]*disktool.Partition, error)
|
||||
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
|
||||
GetNicByMac(mac net.HardwareAddr) *types.SNic
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user