mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 16:13:56 +08:00
Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1760d7b86 | ||
|
|
c456586860 | ||
|
|
71e759a032 | ||
|
|
96ce64d5f0 | ||
|
|
d31802c87b | ||
|
|
d3964bf0d1 | ||
|
|
57dad6281a | ||
|
|
b74130903e | ||
|
|
44046f2861 | ||
|
|
95f7600b67 | ||
|
|
749b819a62 | ||
|
|
f7f7c7be81 | ||
|
|
6a221dbc1e | ||
|
|
002a2af272 | ||
|
|
1757d3d6a9 | ||
|
|
be5a6a93cc | ||
|
|
bbbe78dbef | ||
|
|
a851e01330 | ||
|
|
29d06d52dd | ||
|
|
1a6d4d1035 | ||
|
|
90d649aef9 | ||
|
|
23b99a6232 | ||
|
|
16c38fe6be | ||
|
|
b43f8b3fac | ||
|
|
8e5b74a3f6 | ||
|
|
b0cd3bf999 | ||
|
|
4a15284684 | ||
|
|
d78068d43a | ||
|
|
80dce5eafb | ||
|
|
950696ddb9 | ||
|
|
e7674116e1 | ||
|
|
3fae388db5 | ||
|
|
8f3b8c7ff1 | ||
|
|
a4b1d3952d | ||
|
|
a5ef16243d | ||
|
|
b0823a09bb | ||
|
|
492920ac7c | ||
|
|
f96ac33175 | ||
|
|
1bc16d6f2e | ||
|
|
0ba8cb7fbd | ||
|
|
93bb4022f2 | ||
|
|
bbfb9db90a | ||
|
|
66c81ee548 | ||
|
|
8f3cb9cdbb | ||
|
|
1ac71d0016 | ||
|
|
e8238a2cf5 | ||
|
|
22349276d9 | ||
|
|
d6a9b5dac2 | ||
|
|
0e3aa96f77 | ||
|
|
5306add70a | ||
|
|
f367f1abef | ||
|
|
93dc36134d | ||
|
|
f706d59ac5 | ||
|
|
7438bcab23 | ||
|
|
e038eebeb7 | ||
|
|
bd7d84aebd | ||
|
|
5f6f554464 | ||
|
|
d99d93d046 | ||
|
|
4a856ac688 | ||
|
|
7da0a67af5 | ||
|
|
37c14d756d | ||
|
|
6f1417d268 | ||
|
|
b3105a05d3 | ||
|
|
93ac3260a1 | ||
|
|
3d39c20c91 | ||
|
|
8a0eeb7d67 | ||
|
|
163be04dbb | ||
|
|
06db7339e4 | ||
|
|
e5b3f4673d | ||
|
|
3a6e910580 | ||
|
|
0317fad04e | ||
|
|
af11737e79 | ||
|
|
15bd6bacd6 | ||
|
|
28ba60f630 | ||
|
|
8799a0bcf9 | ||
|
|
6706c39f85 | ||
|
|
8ce183eaf5 | ||
|
|
a5bec974f1 | ||
|
|
ac15981b5d | ||
|
|
3c447a32f6 | ||
|
|
3a8809e060 | ||
|
|
0964c6ad82 | ||
|
|
5d0fd14cb3 | ||
|
|
cd123e007d | ||
|
|
91736710ba | ||
|
|
c2589e7352 | ||
|
|
d454b0a792 | ||
|
|
2a1a640f6b | ||
|
|
9dee4c1b90 | ||
|
|
0fd6481e4d | ||
|
|
d799a71fdb | ||
|
|
436f1e5cb9 | ||
|
|
a92a0e2d05 | ||
|
|
0cafa996d7 | ||
|
|
2a10b72f98 | ||
|
|
31c2b6270a | ||
|
|
a6397d18c2 | ||
|
|
203bf44639 | ||
|
|
d7a4e52b15 | ||
|
|
7946dcef3f | ||
|
|
f77bcd3bbf | ||
|
|
4841fbb843 | ||
|
|
9b8758e191 | ||
|
|
62f5355b11 | ||
|
|
d774581a23 | ||
|
|
062301f54a | ||
|
|
16d13941ce | ||
|
|
a10b1945f6 | ||
|
|
3aadaf15b7 | ||
|
|
7a9b491d13 | ||
|
|
ecbe76e9ff | ||
|
|
41bdfffd57 | ||
|
|
a9c44ed304 | ||
|
|
7a2c2b8047 | ||
|
|
a35a6f3c11 | ||
|
|
5a7876ae47 | ||
|
|
31de731cbd | ||
|
|
8b2680ed56 | ||
|
|
39c35359aa | ||
|
|
a764a64696 | ||
|
|
f05a56aadd | ||
|
|
6cd69d3587 | ||
|
|
2a1bbfd574 | ||
|
|
301006e213 | ||
|
|
950a2c29fb | ||
|
|
558872db27 | ||
|
|
6386391bf4 | ||
|
|
d298c75448 | ||
|
|
28cb75f41b | ||
|
|
560a68d379 | ||
|
|
11f8e4f71f | ||
|
|
9e597db90a | ||
|
|
9c9cb17d32 | ||
|
|
cc96c01c00 | ||
|
|
cb22077722 | ||
|
|
8e3c173373 | ||
|
|
45e092bd2d | ||
|
|
4b2d67de42 | ||
|
|
6677c30a5d | ||
|
|
64593fc882 | ||
|
|
0d7e1a2517 | ||
|
|
6fc835abb9 | ||
|
|
44a9cc5adb | ||
|
|
ff2b7eb345 | ||
|
|
7b5d822373 | ||
|
|
f5a45fc16e | ||
|
|
a583bbc74b | ||
|
|
ece82cce42 | ||
|
|
8042b9430c | ||
|
|
d1cbaead09 | ||
|
|
1768d1e7db | ||
|
|
ff34e93862 | ||
|
|
a891d1d876 | ||
|
|
c7d6bb7811 | ||
|
|
2076a75113 | ||
|
|
5d0d6d960b | ||
|
|
cf89e8a23a | ||
|
|
45994b59d5 | ||
|
|
d2d2934e80 |
@@ -38,7 +38,7 @@ jobs:
|
||||
command: |
|
||||
targets="$(circleci tests glob "cmd/*" | grep -v cmd/host-image | circleci tests split)"
|
||||
echo $targets | tr ' ' '\n'
|
||||
make -j3 $targets
|
||||
make -j2 $targets
|
||||
ls -lh _output/bin/
|
||||
- save_cache:
|
||||
key: onecloud-build-cache-{{ checksum "go.mod" }}-{{ checksum "Makefile" }}
|
||||
|
||||
2
Makefile
2
Makefile
@@ -313,7 +313,7 @@ REGISTRY ?= "registry.cn-beijing.aliyuncs.com/yunionio"
|
||||
VERSION ?= $(shell git describe --exact-match 2> /dev/null || \
|
||||
git describe --match=$(git rev-parse --short=8 HEAD) --always --dirty --abbrev=8)
|
||||
|
||||
image: clean
|
||||
image:
|
||||
mkdir -p $(ROOT_DIR)/_output
|
||||
DEBUG=$(DEBUG) ARCH=$(ARCH) TAG=$(VERSION) REGISTRY=$(REGISTRY) $(ROOT_DIR)/scripts/docker_push.sh $(filter-out $@,$(MAKECMDGOALS))
|
||||
|
||||
|
||||
3
build/docker/Dockerfile.telegraf-raid
Normal file
3
build/docker/Dockerfile.telegraf-raid
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/yunion-rootfs:v1.0
|
||||
|
||||
ADD ./_output/bin/telegraf-raid-plugin /opt/yunion/bin/telegraf-raid-plugin
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
type BaseOptions struct {
|
||||
Debug bool `help:"debug mode"`
|
||||
Help bool `help:"Show help"`
|
||||
CloudEnv string `help:"Cloud environment" default:"$ALIYUN_CLOUD_ENV" choices:"InternationalCloud|FinanceCloud" metavar:"ALIYUN_CLOUD_ENV"`
|
||||
AccessKey string `help:"Access key" default:"$ALIYUN_ACCESS_KEY" metavar:"ALIYUN_ACCESS_KEY"`
|
||||
Secret string `help:"Secret" default:"$ALIYUN_SECRET" metavar:"ALIYUN_SECRET"`
|
||||
RegionId string `help:"RegionId" default:"$ALIYUN_REGION" metavar:"ALIYUN_REGION"`
|
||||
@@ -86,7 +87,9 @@ func newClient(options *BaseOptions) (*aliyun.SRegion, error) {
|
||||
|
||||
cli, err := aliyun.NewAliyunClient(
|
||||
aliyun.NewAliyunClientConfig(
|
||||
options.AccessKey, options.Secret,
|
||||
options.CloudEnv,
|
||||
options.AccessKey,
|
||||
options.Secret,
|
||||
).Debug(options.Debug),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -29,6 +29,7 @@ func init() {
|
||||
Zone string `help:"show images cached at zone"`
|
||||
|
||||
HostSchedtagId string `help:"filter cached image with host schedtag"`
|
||||
Valid *bool `help:"valid cachedimage"`
|
||||
}
|
||||
R(&CachedImageListOptions{}, "cached-image-list", "List cached images", func(s *mcclient.ClientSession, args *CachedImageListOptions) error {
|
||||
params, err := options.ListStructToParams(args)
|
||||
|
||||
@@ -83,6 +83,7 @@ func init() {
|
||||
cmd.Perform("publicip-to-eip", new(options.ServerPublicipToEip))
|
||||
cmd.Perform("set-auto-renew", new(options.ServerSetAutoRenew))
|
||||
cmd.Perform("save-template", new(options.ServerSaveImageOptions))
|
||||
cmd.Perform("remote-update", new(options.ServerRemoteUpdateOptions))
|
||||
|
||||
cmd.Get("vnc", new(options.ServerIdOptions))
|
||||
cmd.Get("desc", new(options.ServerIdOptions))
|
||||
|
||||
@@ -37,6 +37,7 @@ func init() {
|
||||
Schedtag string `help:"filter storage by schedtag"`
|
||||
|
||||
HostSchedtagId string `help:"filter storage by host schedtag"`
|
||||
ImageId string `help:"filter storage by image"`
|
||||
}
|
||||
R(&StorageListOptions{}, "storage-list", "List storages", func(s *mcclient.ClientSession, opts *StorageListOptions) error {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
|
||||
@@ -284,10 +284,7 @@ type IPerformOpt interface {
|
||||
func (cmd ResourceCmd) Perform(action string, args IPerformOpt) {
|
||||
man := cmd.manager
|
||||
callback := func(s *mcclient.ClientSession, args IPerformOpt) error {
|
||||
params, err := args.Params()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := jsonutils.Marshal(args) // .Params()
|
||||
ret, err := man.(modulebase.Manager).PerformAction(s, args.GetId(), action, params)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -488,7 +485,7 @@ func (cmd JointCmd) List(args IJointListOpt) {
|
||||
if len(args.GetMasterOpt()) > 0 {
|
||||
result, err = man.ListDescendent(s, args.GetMasterOpt(), params)
|
||||
} else if len(args.GetSlaveOpt()) > 0 {
|
||||
result, err = man.ListDescendent2(s, args.GetMasterOpt(), params)
|
||||
result, err = man.ListDescendent2(s, args.GetSlaveOpt(), params)
|
||||
} else {
|
||||
result, err = man.List(s, params)
|
||||
}
|
||||
|
||||
@@ -37,11 +37,13 @@ func init() {
|
||||
RoleDomain string `help:"Domain for role"`
|
||||
Limit int64 `help:"maximal returned number of rows"`
|
||||
Offset int64 `help:"offset index of returned results"`
|
||||
Users []string `help:"fitler by users id or name"`
|
||||
Groups []string `help:"fitler by users id or name"`
|
||||
Roles []string `help:"fitler by users id or name"`
|
||||
Projects []string `help:"fitler by users id or name"`
|
||||
Domains []string `help:"fitler by users id or name"`
|
||||
Users []string `help:"fitler by user id or name"`
|
||||
Groups []string `help:"fitler by group id or name"`
|
||||
Roles []string `help:"fitler by role id or name"`
|
||||
Projects []string `help:"fitler by project id or name"`
|
||||
Domains []string `help:"fitler by domain id or name"`
|
||||
|
||||
ProjectDomains []string `help:"filter by project's domain id or name"`
|
||||
}
|
||||
R(&RoleAssignmentsOptions{}, "role-assignments", "List all role assignments", func(s *mcclient.ClientSession, args *RoleAssignmentsOptions) error {
|
||||
query := jsonutils.NewDict()
|
||||
@@ -105,6 +107,9 @@ func init() {
|
||||
if len(args.Domains) > 0 {
|
||||
query.Add(jsonutils.NewStringArray(args.Domains), "domains")
|
||||
}
|
||||
if len(args.ProjectDomains) > 0 {
|
||||
query.Add(jsonutils.NewStringArray(args.ProjectDomains), "project_domains")
|
||||
}
|
||||
if args.Limit > 0 {
|
||||
query.Add(jsonutils.NewInt(args.Limit), "limit")
|
||||
}
|
||||
|
||||
31
cmd/climc/shell/monitor/alertresource.go
Normal file
31
cmd/climc/shell/monitor/alertresource.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/monitor"
|
||||
options "yunion.io/x/onecloud/pkg/mcclient/options/monitor"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd := shell.NewResourceCmd(monitor.AlertResources)
|
||||
cmd.List(new(options.AlertResourceListOptions))
|
||||
cmd.Show(new(options.AlertResourceShowOptions))
|
||||
cmd.BatchDelete(new(options.AlertResourceDeleteOptions))
|
||||
|
||||
jCmd := shell.NewJointCmd(monitor.AlertResourceAlert)
|
||||
jCmd.List(new(options.AlertResourceAlertListOptions))
|
||||
}
|
||||
@@ -12,5 +12,6 @@ func init() {
|
||||
cmd.Show(new(options.CommonAlertShowOptions))
|
||||
cmd.Perform("enable", &options.CommonAlertShowOptions{})
|
||||
cmd.Perform("disable", &options.CommonAlertShowOptions{})
|
||||
cmd.Delete(new(options.CommonAlertDeleteOptions))
|
||||
cmd.BatchDelete(new(options.CommonAlertDeleteOptions))
|
||||
cmd.Perform("config", &options.CommonAlertUpdateOptions{})
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func init() {
|
||||
cmd.Show(new(options.SuggestRuleShowOptions))
|
||||
cmd.Perform("enable", new(options.SuggestRuleShowOptions))
|
||||
cmd.Perform("disable", new(options.SuggestRuleShowOptions))
|
||||
cmd.Delete(new(options.CommonAlertDeleteOptions))
|
||||
cmd.BatchDelete(new(options.CommonAlertDeleteOptions))
|
||||
cmd.Perform("config", new(options.SuggestRuleConfigOptions))
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ type BaseOptions struct {
|
||||
Host string `help:"SSH Host IP" default:"$RAID_HOST" metavar:"RAID_HOST"`
|
||||
Username string `help:"Username, usually root" default:"$RAID_USERNAME" metavar:"RAID_USERNAME"`
|
||||
Password string `help:"Password" default:"$RAID_PASSWORD" metavar:"RAID_PASSWORD"`
|
||||
Driver string `help:"Password" default:"$RAID_DRIVER" metavar:"RAID_DRIVER" choices:"MegaRaid|HPSARaid|Mpt2SAS|MarvelRaid"`
|
||||
Driver string `help:"Raid dirver" default:"$RAID_DRIVER" metavar:"RAID_DRIVER" choices:"MegaRaid|HPSARaid|Mpt2SAS|MarvelRaid"`
|
||||
LocalHost bool `help:"Run raidcli in localhost"`
|
||||
SUBCOMMAND string `help:"s3cli subcommand" subcommand:"true"`
|
||||
}
|
||||
|
||||
@@ -83,43 +84,48 @@ func showErrorAndExit(e error) {
|
||||
}
|
||||
|
||||
func newClient() (raid.IRaidDriver, error) {
|
||||
if len(options.Host) == 0 {
|
||||
return nil, fmt.Errorf("Missing host")
|
||||
}
|
||||
|
||||
if len(options.Username) == 0 {
|
||||
return nil, fmt.Errorf("Missing username")
|
||||
}
|
||||
|
||||
if len(options.Password) == 0 {
|
||||
return nil, fmt.Errorf("Missing password")
|
||||
if options.Debug {
|
||||
raid.Debug = true
|
||||
}
|
||||
|
||||
if len(options.Driver) == 0 {
|
||||
return nil, fmt.Errorf("Missing driver")
|
||||
}
|
||||
|
||||
if options.Debug {
|
||||
raid.Debug = true
|
||||
var drv raid.IRaidDriver
|
||||
if !options.LocalHost {
|
||||
if len(options.Host) == 0 {
|
||||
return nil, fmt.Errorf("Missing host")
|
||||
}
|
||||
|
||||
if len(options.Username) == 0 {
|
||||
return nil, fmt.Errorf("Missing username")
|
||||
}
|
||||
|
||||
if len(options.Password) == 0 {
|
||||
return nil, fmt.Errorf("Missing password")
|
||||
}
|
||||
|
||||
sshClient, err := ssh.NewClient(
|
||||
options.Host,
|
||||
22,
|
||||
options.Username,
|
||||
options.Password,
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ssh client init fail: %s", err)
|
||||
}
|
||||
|
||||
drv = drivers.GetDriver(options.Driver, sshClient)
|
||||
if drv == nil {
|
||||
return nil, fmt.Errorf("not supported driver %s", options.Driver)
|
||||
}
|
||||
} else {
|
||||
drv = drivers.GetLocalDriver(options.Driver)
|
||||
}
|
||||
|
||||
sshClient, err := ssh.NewClient(
|
||||
options.Host,
|
||||
22,
|
||||
options.Username,
|
||||
options.Password,
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ssh client init fail: %s", err)
|
||||
}
|
||||
|
||||
drv := drivers.GetDriver(options.Driver, sshClient)
|
||||
if drv == nil {
|
||||
return nil, fmt.Errorf("not supported driver %s", options.Driver)
|
||||
}
|
||||
|
||||
err = drv.ParsePhyDevs()
|
||||
err := drv.ParsePhyDevs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse phyical devices error %s", err)
|
||||
}
|
||||
|
||||
193
cmd/telegraf-raid-plugin/main.go
Normal file
193
cmd/telegraf-raid-plugin/main.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/detect_storages"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
)
|
||||
|
||||
const (
|
||||
INTERVAL_SECOND = 300
|
||||
TelegrafServer = "http://localhost:8087/write"
|
||||
)
|
||||
|
||||
// Failed, Offline, Degraded, Rebuilding, Out of Sync (OSY)
|
||||
|
||||
func main() {
|
||||
// creates the in-cluster config
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// creates the clientset
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
nodeName := os.Getenv("NODENAME")
|
||||
if len(nodeName) == 0 {
|
||||
log.Fatalf("Missing env nodename")
|
||||
}
|
||||
|
||||
node, err := clientset.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
var masterAddress string
|
||||
if length := len(node.Status.Conditions); length > 0 {
|
||||
if node.Status.Conditions[length-1].Type == v1.NodeReady &&
|
||||
node.Status.Conditions[length-1].Status == v1.ConditionTrue {
|
||||
for _, addr := range node.Status.Addresses {
|
||||
if addr.Type == v1.NodeInternalIP {
|
||||
masterAddress = addr.Address
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Start Colloct Raid Info And Send To Telegraf ...")
|
||||
c := NewRaidInfoCollector(nodeName, masterAddress, INTERVAL_SECOND)
|
||||
c.Start()
|
||||
}
|
||||
|
||||
type RaidInfoCollector struct {
|
||||
waitingReportData []string
|
||||
LastCollectTime time.Time
|
||||
ReportInterval int // seconds
|
||||
Hostname string
|
||||
HostIp string
|
||||
}
|
||||
|
||||
func NewRaidInfoCollector(hostname, hostIp string, interval int) *RaidInfoCollector {
|
||||
return &RaidInfoCollector{
|
||||
waitingReportData: make([]string, 0),
|
||||
ReportInterval: interval,
|
||||
Hostname: hostname,
|
||||
HostIp: hostIp,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RaidInfoCollector) runMain() {
|
||||
timeBegin := time.Now()
|
||||
elapse := timeBegin.Sub(c.LastCollectTime)
|
||||
if elapse < time.Second*time.Duration(c.ReportInterval) {
|
||||
return
|
||||
} else {
|
||||
c.LastCollectTime = timeBegin
|
||||
}
|
||||
c.runMonitor()
|
||||
}
|
||||
|
||||
func (c *RaidInfoCollector) runMonitor() {
|
||||
reportData := c.collectReportData()
|
||||
if len(reportData) > 0 {
|
||||
c.reportRaidInfoToTelegraf(reportData)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RaidInfoCollector) collectReportData() string {
|
||||
if len(c.waitingReportData) > 60 {
|
||||
c.waitingReportData = c.waitingReportData[1:]
|
||||
}
|
||||
return c.CollectReportData()
|
||||
}
|
||||
|
||||
func (c *RaidInfoCollector) CollectReportData() string {
|
||||
raidDiskInfo := make([]*baremetal.BaremetalStorage, 0)
|
||||
// raidDrivers := []string{}
|
||||
for _, drv := range drivers.GetDrivers(drivers.NewExecutor()) {
|
||||
if err := drv.ParsePhyDevs(); err != nil {
|
||||
log.Warningf("Raid driver %s ParsePhyDevs failed: %s", drv.GetName(), err)
|
||||
continue
|
||||
}
|
||||
raidDiskInfo = append(raidDiskInfo, detect_storages.GetRaidDevices(drv)...)
|
||||
// raidDrivers = append(raidDrivers, drv.GetName())
|
||||
}
|
||||
if len(raidDiskInfo) > 0 {
|
||||
ret := c.toTelegrafReportData(raidDiskInfo)
|
||||
return ret
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *RaidInfoCollector) Start() {
|
||||
for {
|
||||
c.runMain()
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
}
|
||||
|
||||
const MEASUREMENT = "host_raid"
|
||||
|
||||
func (c *RaidInfoCollector) toTelegrafReportData(raidDiskInfo []*baremetal.BaremetalStorage) string {
|
||||
tag := fmt.Sprintf("%s=%s,%s=%s", "hostname", c.Hostname, "host_ip", c.HostIp)
|
||||
ret := []string{}
|
||||
for i := 0; i < len(raidDiskInfo); i++ {
|
||||
statArr := []string{}
|
||||
raidDiskInfo[i].Status = strings.ToLower(raidDiskInfo[i].Status)
|
||||
jStat := jsonutils.Marshal(raidDiskInfo[i])
|
||||
jMap, _ := jStat.GetMap()
|
||||
for k, v := range jMap {
|
||||
statArr = append(statArr, fmt.Sprintf("%s=%s", k, v.String()))
|
||||
}
|
||||
stat := strings.Join(statArr, ",")
|
||||
diskTag := fmt.Sprintf(
|
||||
"%s,%s=%s,%s=%d,%s=%d", tag, "driver", raidDiskInfo[i].Driver,
|
||||
"adapter", raidDiskInfo[i].Adapter, "slot", raidDiskInfo[i].Slot,
|
||||
)
|
||||
line := fmt.Sprintf("%s,%s %s", MEASUREMENT, diskTag, stat)
|
||||
ret = append(ret, line)
|
||||
}
|
||||
return strings.Join(ret, "\n")
|
||||
}
|
||||
|
||||
func (c *RaidInfoCollector) reportRaidInfoToTelegraf(data string) {
|
||||
body := strings.NewReader(data)
|
||||
res, err := httputils.Request(
|
||||
httputils.GetDefaultClient(), context.Background(), "POST", TelegrafServer, nil, body, false)
|
||||
if err != nil {
|
||||
log.Errorf("Upload guest metric failed: %s", err)
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != 204 {
|
||||
log.Errorf("upload guest metric failed %d", res.StatusCode)
|
||||
timestamp := time.Now().UnixNano()
|
||||
for _, line := range strings.Split(data, "\n") {
|
||||
c.waitingReportData = append(c.waitingReportData,
|
||||
fmt.Sprintf("%s %d", line, timestamp))
|
||||
}
|
||||
} else {
|
||||
if len(c.waitingReportData) > 0 {
|
||||
oldDatas := strings.Join(c.waitingReportData, "\n")
|
||||
body = strings.NewReader(oldDatas)
|
||||
res, err = httputils.Request(
|
||||
httputils.GetDefaultClient(), context.Background(), "POST", TelegrafServer, nil, body, false)
|
||||
if err == nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
if res.StatusCode == 204 {
|
||||
c.waitingReportData = c.waitingReportData[len(c.waitingReportData):]
|
||||
} else {
|
||||
log.Errorf("upload guest metric failed code: %d", res.StatusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
go.mod
2
go.mod
@@ -146,7 +146,7 @@ require (
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
|
||||
yunion.io/x/pkg v0.0.0-20200814072949-4f1b541857d6
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
|
||||
yunion.io/x/sqlchemy v0.0.0-20201009235752-2ef1a29656b0
|
||||
yunion.io/x/sqlchemy v0.0.0-20201014101037-8fe75542e6d8
|
||||
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce
|
||||
)
|
||||
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1139,7 +1139,7 @@ yunion.io/x/pkg v0.0.0-20200814072949-4f1b541857d6 h1:UarEDTBGkgcgc+nc+PZ75uo9M9
|
||||
yunion.io/x/pkg v0.0.0-20200814072949-4f1b541857d6/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
|
||||
yunion.io/x/sqlchemy v0.0.0-20201009235752-2ef1a29656b0 h1:ETDt3Xc3a6WnbHvhrMUemXVsnWY/RgHrsNRCVFWkCYo=
|
||||
yunion.io/x/sqlchemy v0.0.0-20201009235752-2ef1a29656b0/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
|
||||
yunion.io/x/sqlchemy v0.0.0-20201014101037-8fe75542e6d8 h1:AkPrqO37Yi3aICys9qDjTlSdVVGh2pWQ8ET+dSJmhoI=
|
||||
yunion.io/x/sqlchemy v0.0.0-20201014101037-8fe75542e6d8/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
|
||||
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce h1:kU8xE7O5uZ1GSJVMZHoJ+jrNL7csUQHYGyAPW9QfNpE=
|
||||
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng=
|
||||
|
||||
@@ -71,6 +71,8 @@ const (
|
||||
CLOUD_ACCESS_ENV_AZURE_CHINA = CLOUD_PROVIDER_AZURE
|
||||
CLOUD_ACCESS_ENV_HUAWEI_GLOBAL = CLOUD_PROVIDER_HUAWEI + "-int"
|
||||
CLOUD_ACCESS_ENV_HUAWEI_CHINA = CLOUD_PROVIDER_HUAWEI
|
||||
CLOUD_ACCESS_ENV_ALIYUN_GLOBAL = CLOUD_PROVIDER_ALIYUN
|
||||
CLOUD_ACCESS_ENV_ALIYUN_FINANCE = CLOUD_PROVIDER_ALIYUN + "-fin"
|
||||
CLOUD_ACCESS_ENV_CTYUN_CHINA = CLOUD_PROVIDER_CTYUN
|
||||
)
|
||||
|
||||
|
||||
@@ -98,6 +98,9 @@ type ServerListInput struct {
|
||||
SrcMacCheck *bool `json:"src_mac_check"`
|
||||
|
||||
InstanceType []string `json:"instance_type"`
|
||||
|
||||
// 是否调度到宿主机上
|
||||
WithHost *bool `json:"with_host"`
|
||||
}
|
||||
|
||||
func (input *ServerListInput) AfterUnmarshal() {
|
||||
@@ -409,3 +412,8 @@ type GuestAddSecgroupInput struct {
|
||||
// | 其他 | 5 |
|
||||
SecgroupIds []string `json:"secgroup_ids"`
|
||||
}
|
||||
|
||||
type ServerRemoteUpdateInput struct {
|
||||
// 是否覆盖替换所有标签
|
||||
ReplaceTags *bool `json:"replace_tags" help:"replace all remote tags"`
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@ type CachedimageListInput struct {
|
||||
|
||||
// filter by host schedtag
|
||||
HostSchedtagId string `json:"host_schedtag_id"`
|
||||
|
||||
// valid cachedimage
|
||||
Valid *bool `json:"valid"`
|
||||
}
|
||||
|
||||
type ExternalProjectListInput struct {
|
||||
|
||||
@@ -187,6 +187,12 @@ type NetworkCreateInput struct {
|
||||
|
||||
// 是否加入自动分配地址池
|
||||
IsAutoAlloc *bool `json:"is_auto_alloc"`
|
||||
|
||||
// VlanId
|
||||
VlanId *int `json:"vlan_id"`
|
||||
|
||||
// deprecated
|
||||
Vlan *int `json:"vlan" yunion-deprecated-by:"vlan_id"`
|
||||
}
|
||||
|
||||
type NetworkDetails struct {
|
||||
|
||||
@@ -21,10 +21,10 @@ type SnapshotPolicyDetails struct {
|
||||
|
||||
SSnapshotPolicy
|
||||
|
||||
RetentionDays int `json:"retention_days"`
|
||||
RepeatWeekdays []int `json:"repeat_weekdays"`
|
||||
TimePoints []int `json:"time_points"`
|
||||
IsActivated *bool `json:"is_activated,omitempty"`
|
||||
RetentionDays int `json:"retention_days"`
|
||||
RepeatWeekdaysDisplay []int `json:"repeat_weekdays_display"`
|
||||
TimePointsDisplay []int `json:"time_points_display"`
|
||||
IsActivated *bool `json:"is_activated,omitempty"`
|
||||
|
||||
BindingDiskCount int `json:"binding_disk_count"`
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ const (
|
||||
STORAGE_GOOGLE_LOCAL_SSD = "local-ssd" //本地SSD暂存盘 (最多8个)
|
||||
STORAGE_GOOGLE_PD_STANDARD = "pd-standard" //标准永久性磁盘
|
||||
STORAGE_GOOGLE_PD_SSD = "pd-ssd" //SSD永久性磁盘
|
||||
STORAGE_GOOGLE_PD_BALANCED = "pd-balanced" //平衡永久性磁盘
|
||||
|
||||
// ctyun storage type
|
||||
STORAGE_CTYUN_SSD = "SSD" // 超高IO云硬盘
|
||||
@@ -186,4 +187,7 @@ type StorageListInput struct {
|
||||
|
||||
// filter by host schedtag
|
||||
HostSchedtagId string `json:"host_schedtag_id"`
|
||||
|
||||
// filter by cachedimage
|
||||
ImageId string `json:"image_id"`
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ type RoleAssignmentsInput struct {
|
||||
Projects []string `json:"projects"`
|
||||
Domains []string `json:"domains"`
|
||||
|
||||
ProjectDomains []string `json:"project_domains"`
|
||||
|
||||
IncludeNames *bool `json:"include_names"`
|
||||
Effective *bool `json:"effective"`
|
||||
IncludeSubtree *bool `json:"include_subtree"`
|
||||
|
||||
@@ -195,8 +195,19 @@ type MetadataResourceListInput struct {
|
||||
// 通过标签过滤
|
||||
OrderByTag string `json:"order_by_tag"`
|
||||
|
||||
// 返回资源的标签不包含特定的用户标签
|
||||
WithoutUserMeta bool `json:"without_user_meta"`
|
||||
// deprecated
|
||||
// 返回资源的标签不包含用户标签
|
||||
WithoutUserMeta *bool `json:"without_user_meta"`
|
||||
|
||||
// 返回包含用户标签的资源
|
||||
WithUserMeta *bool `json:"with_user_meta"`
|
||||
|
||||
// 返回包含外部标签的资源
|
||||
WithCloudMeta *bool `json:"with_cloud_meta"`
|
||||
|
||||
// 返回包含任意标签的资源
|
||||
WithAnyMeta *bool `json:"with_any_meta"`
|
||||
|
||||
// 返回列表数据中包含资源的标签数据(Metadata)
|
||||
WithMeta *bool `json:"with_meta"`
|
||||
}
|
||||
|
||||
@@ -39,6 +39,6 @@ type AlertRecordRule struct {
|
||||
// 比较运算符, 比如: >, <, >=, <=
|
||||
Comparator string `json:"comparator"`
|
||||
// 报警阀值
|
||||
Threshold float64 `json:"threshold"`
|
||||
Period string `json:"period"`
|
||||
Threshold string `json:"threshold"`
|
||||
Period string `json:"period"`
|
||||
}
|
||||
|
||||
77
pkg/apis/monitor/alertresource.go
Normal file
77
pkg/apis/monitor/alertresource.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
)
|
||||
|
||||
type AlertResourceType string
|
||||
|
||||
const (
|
||||
// AlertResourceTypeNode means onecloud system infrastructure controller or host node
|
||||
AlertResourceTypeNode AlertResourceType = "node"
|
||||
// AlertResourceTypeCloudaccount means cloudaccount resource
|
||||
AlertResourceTypeCloudaccount AlertResourceType = "cloudaccount"
|
||||
// AlertResourceTypeVM means virtual machine guest resource
|
||||
// AlertResourceTypeVM AlertResourceType = "vm"
|
||||
)
|
||||
|
||||
type AlertResourceCreateInput struct {
|
||||
apis.StandaloneResourceCreateInput
|
||||
|
||||
Type AlertResourceType `json:"type"`
|
||||
}
|
||||
|
||||
type AlertResourceListInput struct {
|
||||
apis.StandaloneResourceListInput
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type AlertResourceAttachInput struct {
|
||||
apis.Meta
|
||||
|
||||
AlertResourceId string `json:"alert_resource_id"`
|
||||
AlertId string `json:"alert_id"`
|
||||
AlertRecordId string `json:"alert_record_id"`
|
||||
Data EvalMatch `json:"data"`
|
||||
}
|
||||
|
||||
type AlertResourceDetails struct {
|
||||
apis.StandaloneResourceDetails
|
||||
Count int `json:"count"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
}
|
||||
|
||||
type AlertResourceAlertListInput struct {
|
||||
apis.JointResourceBaseListInput
|
||||
AlertResourceId string `json:"alert_resource_id"`
|
||||
AlertId string `json:"alert_id"`
|
||||
}
|
||||
|
||||
type AlertResourceJointBaseDetails struct {
|
||||
apis.JointResourceBaseDetails
|
||||
|
||||
AlertResource string `json:"alert_resource"`
|
||||
Type AlertResourceType `json:"type"`
|
||||
}
|
||||
|
||||
type AlertResourceAlertDetails struct {
|
||||
AlertResourceJointBaseDetails
|
||||
Alert string `json:"alert"`
|
||||
AlertType string `json:"alert_type"`
|
||||
Level string `json:"level"`
|
||||
CommonAlertMetricDetails []*CommonAlertMetricDetails `json:"common_alert_metric_details"`
|
||||
}
|
||||
@@ -86,6 +86,8 @@ type CommonAlertUpdateInput struct {
|
||||
Channel []string `json:"channel"`
|
||||
// 通知接受者
|
||||
Recipients []string `json:"recipients"`
|
||||
// systemalert policy may need update through operator
|
||||
ForceUpdate bool `json:"force_update"`
|
||||
}
|
||||
|
||||
type CommonAlertDetails struct {
|
||||
@@ -105,13 +107,14 @@ type CommonAlertMetricDetails struct {
|
||||
Comparator string `json:"comparator"`
|
||||
Threshold float64 `json:"threshold"`
|
||||
// metric points'value的运算方式
|
||||
Reduce string `json:"reduce"`
|
||||
DB string `json:"db"`
|
||||
Measurement string `json:"measurement"`
|
||||
MeasurementDisplayName string `json:"measurement_display_name"`
|
||||
ResType string `json:"res_type"`
|
||||
Field string `json:"field"`
|
||||
Groupby string `json:"groupby"`
|
||||
Reduce string `json:"reduce"`
|
||||
DB string `json:"db"`
|
||||
Measurement string `json:"measurement"`
|
||||
MeasurementDisplayName string `json:"measurement_display_name"`
|
||||
ResType string `json:"res_type"`
|
||||
Field string `json:"field"`
|
||||
Groupby string `json:"groupby"`
|
||||
Filters []MetricQueryTag `json:"filters"`
|
||||
FieldDescription MetricFieldDetail
|
||||
FieldOpt string `json:"field_opt"`
|
||||
}
|
||||
|
||||
@@ -41,8 +41,11 @@ type MetricFunc struct {
|
||||
}
|
||||
|
||||
type MetricInputQuery struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Scope string `json:"scope"`
|
||||
//default group by
|
||||
Unit bool `json:"unit"`
|
||||
Interval string `json:"interval"`
|
||||
DomainId string `json:"domain_id"`
|
||||
ProjectId string `json:"project_id"`
|
||||
|
||||
@@ -29,6 +29,7 @@ const (
|
||||
FEISHU_ROBOT = "feishu-robot"
|
||||
DINGTALK_ROBOT = "dingtalk-robot"
|
||||
WORKWX_ROBOT = "workwx-robot"
|
||||
WEBHOOK = "webhook"
|
||||
|
||||
ROBOT = "robot"
|
||||
|
||||
@@ -60,4 +61,7 @@ const (
|
||||
TEMPLATE_TYPE_TITLE = "title"
|
||||
TEMPLATE_TYPE_CONTENT = "content"
|
||||
TEMPLATE_TYPE_REMOTE = "remote"
|
||||
|
||||
CTYPE_ROBOT_YES = "yes"
|
||||
CTYPE_ROBOT_ONLY = "only"
|
||||
)
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
"yunion.io/x/onecloud/pkg/util/sysutils"
|
||||
)
|
||||
|
||||
@@ -48,7 +47,7 @@ func GetRaidLogicVolumes(drv raid.IRaidDriver) ([]*raid.RaidLogicalVolume, error
|
||||
return lvs, nil
|
||||
}
|
||||
|
||||
func DetectStorageInfo(term *ssh.Client, wait bool) ([]*baremetal.BaremetalStorage, []*baremetal.BaremetalStorage, []*baremetal.BaremetalStorage, error) {
|
||||
func DetectStorageInfo(term raid.IExecTerm, wait bool) ([]*baremetal.BaremetalStorage, []*baremetal.BaremetalStorage, []*baremetal.BaremetalStorage, error) {
|
||||
raidDiskInfo := make([]*baremetal.BaremetalStorage, 0)
|
||||
lvDiskInfo := make([]*raid.RaidLogicalVolume, 0)
|
||||
|
||||
|
||||
@@ -29,10 +29,9 @@ import (
|
||||
_ "yunion.io/x/onecloud/pkg/baremetal/utils/raid/mvcli"
|
||||
_ "yunion.io/x/onecloud/pkg/baremetal/utils/raid/sas2iru"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
func GetDriver(name string, term *ssh.Client) raid.IRaidDriver {
|
||||
func GetDriver(name string, term raid.IExecTerm) raid.IRaidDriver {
|
||||
factory := raid.RaidDrivers[name]
|
||||
if factory == nil {
|
||||
return nil
|
||||
@@ -40,7 +39,15 @@ func GetDriver(name string, term *ssh.Client) raid.IRaidDriver {
|
||||
return factory(term)
|
||||
}
|
||||
|
||||
func GetDriverWithInit(name string, term *ssh.Client) (raid.IRaidDriver, error) {
|
||||
func GetLocalDriver(name string) raid.IRaidDriver {
|
||||
factory := raid.RaidDrivers[name]
|
||||
if factory == nil {
|
||||
return nil
|
||||
}
|
||||
return factory(NewExecutor())
|
||||
}
|
||||
|
||||
func GetDriverWithInit(name string, term raid.IExecTerm) (raid.IRaidDriver, error) {
|
||||
drv := GetDriver(name, term)
|
||||
if drv == nil {
|
||||
return nil, errors.Errorf("Not found raid driver %q", name)
|
||||
@@ -48,7 +55,7 @@ func GetDriverWithInit(name string, term *ssh.Client) (raid.IRaidDriver, error)
|
||||
return drv, drv.ParsePhyDevs()
|
||||
}
|
||||
|
||||
func GetDriverByKernelModule(module string, term *ssh.Client) (raid.IRaidDriver, error) {
|
||||
func GetDriverByKernelModule(module string, term raid.IExecTerm) (raid.IRaidDriver, error) {
|
||||
name := ""
|
||||
switch module {
|
||||
case raid.MODULE_MEGARAID:
|
||||
@@ -64,7 +71,7 @@ func GetDriverByKernelModule(module string, term *ssh.Client) (raid.IRaidDriver,
|
||||
return GetDriverWithInit(name, term)
|
||||
}
|
||||
|
||||
func GetDrivers(term *ssh.Client) []raid.IRaidDriver {
|
||||
func GetDrivers(term raid.IExecTerm) []raid.IRaidDriver {
|
||||
ret := []raid.IRaidDriver{}
|
||||
for _, factory := range raid.RaidDrivers {
|
||||
ret = append(ret, factory(term))
|
||||
|
||||
56
pkg/baremetal/utils/raid/drivers/executor.go
Normal file
56
pkg/baremetal/utils/raid/drivers/executor.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package drivers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type Executor struct{}
|
||||
|
||||
func (e *Executor) Run(cmds ...string) ([]string, error) {
|
||||
return e.run(true, cmds, nil)
|
||||
}
|
||||
|
||||
func (e *Executor) RunWithInput(input io.Reader, cmds ...string) ([]string, error) {
|
||||
return e.run(true, cmds, input)
|
||||
}
|
||||
|
||||
func (e *Executor) run(parseOutput bool, cmds []string, input io.Reader) ([]string, error) {
|
||||
ret := []string{}
|
||||
for _, cmd := range cmds {
|
||||
log.Debugf("Run command: %s", cmd)
|
||||
proc := exec.Command("sh", "-c", cmd)
|
||||
var stdOut bytes.Buffer
|
||||
var stdErr bytes.Buffer
|
||||
proc.Stdout = &stdOut
|
||||
proc.Stderr = &stdErr
|
||||
proc.Stdin = input
|
||||
if err := proc.Run(); err != nil {
|
||||
var outputErr error
|
||||
errMsg := stdErr.String()
|
||||
if len(stdOut.String()) != 0 {
|
||||
errMsg = fmt.Sprintf("%s %s", errMsg, stdOut.String())
|
||||
}
|
||||
outputErr = errors.Error(errMsg)
|
||||
err = errors.Wrapf(outputErr, "%q error: %v, cmd error", cmd, err)
|
||||
return nil, err
|
||||
}
|
||||
if parseOutput {
|
||||
ret = append(ret, ssh.ParseOutput(stdOut.Bytes())...)
|
||||
} else {
|
||||
ret = append(ret, stdOut.String())
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func NewExecutor() *Executor {
|
||||
return new(Executor)
|
||||
}
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/regutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type HPSARaidPhyDev struct {
|
||||
@@ -347,11 +346,11 @@ func (adapter *HPSARaidAdaptor) RemoveLogicVolumes() error {
|
||||
}
|
||||
|
||||
type HPSARaid struct {
|
||||
term *ssh.Client
|
||||
term raid.IExecTerm
|
||||
adapters []*HPSARaidAdaptor
|
||||
}
|
||||
|
||||
func NewHPSARaid(term *ssh.Client) raid.IRaidDriver {
|
||||
func NewHPSARaid(term raid.IExecTerm) raid.IRaidDriver {
|
||||
return &HPSARaid{
|
||||
term: term,
|
||||
adapters: make([]*HPSARaidAdaptor, 0),
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package raid
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
)
|
||||
@@ -41,3 +43,8 @@ type IRaidAdapter interface {
|
||||
BuildRaid10(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error
|
||||
BuildNoneRaid(devs []*baremetal.BaremetalStorage) error
|
||||
}
|
||||
|
||||
type IExecTerm interface {
|
||||
Run(cmds ...string) ([]string, error)
|
||||
RunWithInput(input io.Reader, cmds ...string) ([]string, error)
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ import (
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
raiddrivers "yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/regutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -320,7 +320,7 @@ func (adapter *MegaRaidAdaptor) GetIndex() int {
|
||||
return adapter.index
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) getTerm() *ssh.Client {
|
||||
func (adapter *MegaRaidAdaptor) getTerm() raid.IExecTerm {
|
||||
return adapter.raid.term
|
||||
}
|
||||
|
||||
@@ -376,7 +376,7 @@ func (adapter *MegaRaidAdaptor) parseLogicVolumes(lines []string) ([]*raiddriver
|
||||
return lvs, nil
|
||||
}
|
||||
|
||||
func getLogicVolumeDeviceById(hostNum, scsiId int, term *ssh.Client) (string, error) {
|
||||
func getLogicVolumeDeviceById(hostNum, scsiId int, term raid.IExecTerm) (string, error) {
|
||||
items, err := raiddrivers.SGMap(term)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -892,13 +892,13 @@ func (adapter *MegaRaidAdaptor) clearJBODDisks() {
|
||||
}
|
||||
|
||||
type MegaRaid struct {
|
||||
term *ssh.Client
|
||||
term raid.IExecTerm
|
||||
adapters []*MegaRaidAdaptor
|
||||
PhyDevsCnt int
|
||||
Capacity int64
|
||||
}
|
||||
|
||||
func NewMegaRaid(term *ssh.Client) raiddrivers.IRaidDriver {
|
||||
func NewMegaRaid(term raid.IExecTerm) raiddrivers.IRaidDriver {
|
||||
return &MegaRaid{
|
||||
term: term,
|
||||
adapters: make([]*MegaRaidAdaptor, 0),
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type MarvelRaidPhyDev struct {
|
||||
@@ -243,11 +242,11 @@ func (adapter *MarvelRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStora
|
||||
}
|
||||
|
||||
type MarvelRaid struct {
|
||||
term *ssh.Client
|
||||
term raid.IExecTerm
|
||||
adapters []*MarvelRaidAdaptor
|
||||
}
|
||||
|
||||
func NewMarvelRaid(term *ssh.Client) raid.IRaidDriver {
|
||||
func NewMarvelRaid(term raid.IExecTerm) raid.IRaidDriver {
|
||||
return &MarvelRaid{
|
||||
term: term,
|
||||
adapters: make([]*MarvelRaidAdaptor, 0),
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
"yunion.io/x/onecloud/pkg/util/sysutils"
|
||||
)
|
||||
|
||||
@@ -45,7 +44,7 @@ const (
|
||||
UnknownLogicalVolumeIndex = MaxInt
|
||||
)
|
||||
|
||||
type RaidDriverFactory func(term *ssh.Client) IRaidDriver
|
||||
type RaidDriverFactory func(term IExecTerm) IRaidDriver
|
||||
|
||||
type sRaidDrivers map[string]RaidDriverFactory
|
||||
|
||||
@@ -106,7 +105,7 @@ func (dev *RaidBasePhyDev) ToBaremetalStorage(index int) *baremetal.BaremetalSto
|
||||
}
|
||||
}
|
||||
|
||||
func GetModules(term *ssh.Client) []string {
|
||||
func GetModules(term IExecTerm) []string {
|
||||
ret := []string{}
|
||||
lines, err := term.Run("/sbin/lsmod")
|
||||
if err != nil {
|
||||
@@ -142,7 +141,7 @@ type RaidLogicalVolume struct {
|
||||
BlockDev string
|
||||
}
|
||||
|
||||
func SGMap(term *ssh.Client) ([]compute.SGMapItem, error) {
|
||||
func SGMap(term IExecTerm) ([]compute.SGMapItem, error) {
|
||||
lines, err := term.Run("/usr/bin/sg_map -x")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "run sg_map")
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type Mpt2SASRaidPhyDev struct {
|
||||
@@ -307,12 +306,12 @@ func (adapter *Mpt2SASRaidAdaptor) RemoveLogicVolumes() error {
|
||||
}
|
||||
|
||||
type Mpt2SASRaid struct {
|
||||
term *ssh.Client
|
||||
term raid.IExecTerm
|
||||
utility string
|
||||
adapters []*Mpt2SASRaidAdaptor
|
||||
}
|
||||
|
||||
func NewMpt2SASRaid(term *ssh.Client) raid.IRaidDriver {
|
||||
func NewMpt2SASRaid(term raid.IExecTerm) raid.IRaidDriver {
|
||||
return &Mpt2SASRaid{
|
||||
term: term,
|
||||
adapters: make([]*Mpt2SASRaidAdaptor, 0),
|
||||
|
||||
@@ -30,6 +30,7 @@ type SEndpointChangeManager struct {
|
||||
func newEndpointChangeManager() *SEndpointChangeManager {
|
||||
man := &SEndpointChangeManager{}
|
||||
man.InitSync(man)
|
||||
man.FirstSync()
|
||||
return man
|
||||
}
|
||||
|
||||
|
||||
@@ -301,6 +301,7 @@ func FetchCustomizeColumns(
|
||||
retVal := make([]*jsonutils.JSONDict, ret[0].Len())
|
||||
for i := 0; i < ret[0].Len(); i += 1 {
|
||||
jsonDict := ValueToJSONDict(ret[0].Index(i))
|
||||
// NOTE: don't use obj update jsonDict as retval
|
||||
jsonDict.Update(jsonutils.Marshal(objs[i]).(*jsonutils.JSONDict))
|
||||
retVal[i] = jsonDict
|
||||
}
|
||||
|
||||
@@ -928,6 +928,12 @@ func (dispatcher *DBModelDispatcher) Get(ctx context.Context, idStr string, quer
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if data != nil {
|
||||
if dataDict, ok := data.(*jsonutils.JSONDict); ok {
|
||||
i18nDict := dispatcher.modelManager.GetI18N(ctx, idStr, data)
|
||||
if i18nDict != nil {
|
||||
dataDict.Set("_i18n", i18nDict)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -107,12 +107,7 @@ func (manager *SDomainizedResourceBaseManager) ListItemFilter(
|
||||
) (*sqlchemy.SQuery, error) {
|
||||
if len(query.ProjectDomainIds) > 0 {
|
||||
// make sure ids are not utf8 string
|
||||
idList := make([]string, 0)
|
||||
for _, pid := range query.ProjectDomainIds {
|
||||
if !stringutils2.IsUtf8(pid) {
|
||||
idList = append(idList, pid)
|
||||
}
|
||||
}
|
||||
idList := stringutils2.RemoveUtf8Strings(query.ProjectDomainIds)
|
||||
tenants := TenantCacheManager.GetDomainQuery().SubQuery()
|
||||
subq := tenants.Query(tenants.Field("id")).Filter(sqlchemy.OR(
|
||||
sqlchemy.In(tenants.Field("id"), idList),
|
||||
|
||||
@@ -127,6 +127,8 @@ type IModelManager interface {
|
||||
QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error)
|
||||
|
||||
GetPagingConfig() *SPagingConfig
|
||||
|
||||
GetI18N(ctx context.Context, idstr string, resObj jsonutils.JSONObject) *jsonutils.JSONDict
|
||||
}
|
||||
|
||||
type IModel interface {
|
||||
@@ -246,6 +248,10 @@ type IMetadataBaseModelManager interface {
|
||||
GetMetadataHiddenKeys() []string
|
||||
}
|
||||
|
||||
type IMetadataBaseModel interface {
|
||||
OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential)
|
||||
}
|
||||
|
||||
type IStandaloneModelManager interface {
|
||||
IResourceModelManager
|
||||
|
||||
@@ -282,6 +288,8 @@ type IStandaloneModel interface {
|
||||
GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error)
|
||||
|
||||
IsShared() bool
|
||||
|
||||
IMetadataBaseModel
|
||||
}
|
||||
|
||||
type IDomainLevelModelManager interface {
|
||||
|
||||
@@ -26,7 +26,8 @@ func TestEctdLockManager(t *testing.T) {
|
||||
shared := newSharedObject()
|
||||
for i := 0; i < 4; i++ {
|
||||
lockman, err := NewEtcdLockManager(&SEtcdLockManagerConfig{
|
||||
Endpoints: []string{"localhost:2379"},
|
||||
LockPrefix: "test-etcd-lock-manager",
|
||||
Endpoints: []string{"localhost:2379"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Skipf("new etcd lockman: %v", err)
|
||||
|
||||
@@ -492,6 +492,7 @@ func (manager *SMetadataManager) SetValues(ctx context.Context, obj IModel, stor
|
||||
}
|
||||
|
||||
newRecord := SMetadata{}
|
||||
newRecord.SetModelManager(manager, &newRecord)
|
||||
|
||||
newRecord.ObjId = obj.GetId()
|
||||
newRecord.ObjType = obj.GetModelManager().Keyword()
|
||||
|
||||
@@ -70,10 +70,34 @@ func (meta *SMetadataResourceBaseModelManager) ListItemFilter(
|
||||
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
||||
}
|
||||
|
||||
if input.WithoutUserMeta {
|
||||
if input.WithoutUserMeta != nil || input.WithUserMeta != nil {
|
||||
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
||||
sq := metadatas.Query(metadatas.Field("obj_id")).Startswith("key", USER_TAG_PREFIX).Distinct().SubQuery()
|
||||
q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
||||
if (input.WithoutUserMeta != nil && *input.WithoutUserMeta) || (input.WithUserMeta != nil && !*input.WithUserMeta) {
|
||||
q = q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
||||
} else {
|
||||
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
||||
}
|
||||
}
|
||||
|
||||
if input.WithCloudMeta != nil {
|
||||
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
||||
sq := metadatas.Query(metadatas.Field("obj_id")).Startswith("key", CLOUD_TAG_PREFIX).Distinct().SubQuery()
|
||||
if *input.WithCloudMeta {
|
||||
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
||||
} else {
|
||||
q = q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
||||
}
|
||||
}
|
||||
|
||||
if input.WithAnyMeta != nil {
|
||||
metadatas := Metadata.Query().Equals("obj_type", manager.Keyword()).SubQuery()
|
||||
sq := metadatas.Query(metadatas.Field("obj_id")).Distinct().SubQuery()
|
||||
if *input.WithAnyMeta {
|
||||
q = q.Filter(sqlchemy.In(q.Field("id"), sq))
|
||||
} else {
|
||||
q = q.Filter(sqlchemy.NotIn(q.Field("id"), sq))
|
||||
}
|
||||
}
|
||||
|
||||
return q
|
||||
|
||||
@@ -359,14 +359,15 @@ func (manager *SModelBaseManager) GetPropertyDistinctField(ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
var res = jsonutils.NewDict()
|
||||
q := im.Query()
|
||||
q, err = ListItemQueryFilters(im, ctx, q, userCred, query, policy.PolicyActionList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var backupQuery = *q
|
||||
|
||||
var (
|
||||
backupQuery = *q
|
||||
res = jsonutils.NewDict()
|
||||
)
|
||||
// query field
|
||||
for i := 0; i < len(fields); i++ {
|
||||
var nq = backupQuery
|
||||
@@ -424,6 +425,10 @@ func (manager *SModelBaseManager) OnCreateFailed(ctx context.Context, userCred m
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) GetI18N(ctx context.Context, idstr string, resObj jsonutils.JSONObject) *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SModelBase) GetId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -91,6 +91,13 @@ func GenerateName(manager IModelManager, ownerId mcclient.IIdentityProvider, hin
|
||||
return GenerateName2(manager, ownerId, hint, nil, 1)
|
||||
}
|
||||
|
||||
func GenerateAlterName(model IModel, hint string) (string, error) {
|
||||
if hint == model.GetName() {
|
||||
return hint, nil
|
||||
}
|
||||
return GenerateName2(nil, nil, hint, model, 1)
|
||||
}
|
||||
|
||||
func GenerateName2(manager IModelManager, ownerId mcclient.IIdentityProvider, hint string, model IModel, baseIndex int) (string, error) {
|
||||
_, pattern, patternLen := stringutils.ParseNamePattern(hint)
|
||||
var name string
|
||||
|
||||
@@ -45,31 +45,29 @@ type SOpsLogManager struct {
|
||||
type SOpsLog struct {
|
||||
SModelBase
|
||||
|
||||
Id int64 `primary:"true" auto_increment:"true" list:"user"` // = Column(BigInteger, primary_key=True)
|
||||
ObjType string `width:"40" charset:"ascii" nullable:"false" list:"user" create:"required"` // = Column(VARCHAR(40, charset='ascii'), nullable=False)
|
||||
ObjId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=False)
|
||||
ObjName string `width:"128" charset:"utf8" nullable:"false" list:"user" create:"required"` //= Column(VARCHAR(128, charset='utf8'), nullable=False)
|
||||
Action string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"required"` //= Column(VARCHAR(32, charset='ascii'), nullable=False)
|
||||
Id int64 `primary:"true" auto_increment:"true" list:"user"`
|
||||
ObjType string `width:"40" charset:"ascii" nullable:"false" list:"user" create:"required"`
|
||||
ObjId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
|
||||
ObjName string `width:"128" charset:"utf8" nullable:"false" list:"user" create:"required"`
|
||||
Action string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"required"`
|
||||
Notes string `charset:"utf8" list:"user" create:"required"`
|
||||
|
||||
ProjectId string `name:"tenant_id" width:"128" charset:"ascii" list:"user" create:"required" index:"true"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
||||
Project string `name:"tenant" width:"128" charset:"utf8" list:"user" create:"required"` // tenant = Column(VARCHAR(128, charset='utf8'))
|
||||
ProjectId string `name:"tenant_id" width:"128" charset:"ascii" list:"user" create:"optional" index:"true"`
|
||||
Project string `name:"tenant" width:"128" charset:"utf8" list:"user" create:"optional"`
|
||||
|
||||
ProjectDomainId string `name:"project_domain_id" default:"default" width:"128" charset:"ascii" list:"user" create:"required"`
|
||||
ProjectDomain string `name:"project_domain" default:"Default" width:"128" charset:"utf8" list:"user" create:"required"`
|
||||
ProjectDomainId string `name:"project_domain_id" default:"default" width:"128" charset:"ascii" list:"user" create:"optional"`
|
||||
ProjectDomain string `name:"project_domain" default:"Default" width:"128" charset:"utf8" list:"user" create:"optional"`
|
||||
|
||||
UserId string `width:"128" charset:"ascii" list:"user" create:"required"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
||||
User string `width:"128" charset:"utf8" list:"user" create:"required"` // = Column(VARCHAR(128, charset='utf8'))
|
||||
UserId string `width:"128" charset:"ascii" list:"user" create:"required"`
|
||||
User string `width:"128" charset:"utf8" list:"user" create:"required"`
|
||||
DomainId string `width:"128" charset:"ascii" list:"user" create:"optional"`
|
||||
Domain string `width:"128" charset:"utf8" list:"user" create:"optional"`
|
||||
Roles string `width:"64" charset:"ascii" list:"user" create:"optional"` // = Column(VARCHAR(64, charset='ascii'))
|
||||
Roles string `width:"64" charset:"ascii" list:"user" create:"optional"`
|
||||
|
||||
// BillingType string `width:"64" charset:"ascii" default:"postpaid" list:"user" create:"user"` // billing_type = Column(VARCHAR(64, charset='ascii'), nullable=True)
|
||||
OpsTime time.Time `nullable:"false" list:"user"` // = Column(DateTime, nullable=False)
|
||||
OpsTime time.Time `nullable:"false" list:"user"`
|
||||
|
||||
OwnerDomainId string `name:"owner_domain_id" default:"default" width:"128" charset:"ascii" list:"user" create:"optional"`
|
||||
OwnerProjectId string `name:"owner_tenant_id" width:"128" charset:"ascii" list:"user" create:"optional"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
||||
// owner_user_id = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
||||
OwnerProjectId string `name:"owner_tenant_id" width:"128" charset:"ascii" list:"user" create:"optional"`
|
||||
}
|
||||
|
||||
var OpsLog *SOpsLogManager
|
||||
@@ -434,6 +432,7 @@ func (manager *SOpsLogManager) ValidateCreateData(ctx context.Context,
|
||||
query jsonutils.JSONObject,
|
||||
data apis.OpsLogCreateInput,
|
||||
) (apis.OpsLogCreateInput, error) {
|
||||
data.User = ownerId.GetUserName()
|
||||
return data, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -102,12 +102,7 @@ func (manager *SProjectizedResourceBaseManager) ListItemFilter(
|
||||
}
|
||||
if len(query.ProjectIds) > 0 {
|
||||
// make sure ids are not utf8 string
|
||||
idList := make([]string, 0)
|
||||
for _, pid := range query.ProjectIds {
|
||||
if !stringutils2.IsUtf8(pid) {
|
||||
idList = append(idList, pid)
|
||||
}
|
||||
}
|
||||
idList := stringutils2.RemoveUtf8Strings(query.ProjectIds)
|
||||
tenants := TenantCacheManager.GetTenantQuery().SubQuery()
|
||||
subq := tenants.Query(tenants.Field("id")).Filter(sqlchemy.OR(
|
||||
sqlchemy.In(tenants.Field("id"), idList),
|
||||
|
||||
@@ -33,6 +33,7 @@ var (
|
||||
func init() {
|
||||
quotaManagerTable = make(map[reflect.Type]IQuotaManager)
|
||||
|
||||
db.AddUsages = AddUsages
|
||||
db.CancelUsages = CancelUsages
|
||||
db.CancelPendingUsagesInContext = cancelPendingUsagesInContext
|
||||
db.InitPendingUsagesInContext = initPendingUsagesInContext
|
||||
|
||||
@@ -266,32 +266,81 @@ func (model *SStandaloneResourceBase) GetMetadataJson(key string, userCred mccli
|
||||
return Metadata.GetJsonValue(model, key, userCred)
|
||||
}
|
||||
|
||||
func isUserMetadata(key string) bool {
|
||||
return strings.HasPrefix(key, USER_TAG_PREFIX)
|
||||
}
|
||||
|
||||
func containsUserMetadata(dict map[string]interface{}) bool {
|
||||
for k := range dict {
|
||||
if isUserMetadata(k) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) SetMetadata(ctx context.Context, key string, value interface{}, userCred mcclient.TokenCredential) error {
|
||||
return Metadata.SetValue(ctx, model, key, value, userCred)
|
||||
err := Metadata.SetValue(ctx, model, key, value, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetValue")
|
||||
}
|
||||
if isUserMetadata(key) {
|
||||
model.GetIStandaloneModel().OnMetadataUpdated(ctx, userCred)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) SetAllMetadata(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||||
return Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||||
err := Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetValuesWithLog")
|
||||
}
|
||||
if containsUserMetadata(dictstore) {
|
||||
model.GetIStandaloneModel().OnMetadataUpdated(ctx, userCred)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) SetUserMetadataValues(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||||
return Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||||
err := Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetValuesWithLog")
|
||||
}
|
||||
model.GetIStandaloneModel().OnMetadataUpdated(ctx, userCred)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) SetUserMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||||
return Metadata.SetAll(ctx, model, dictstore, userCred, USER_TAG_PREFIX)
|
||||
err := Metadata.SetAll(ctx, model, dictstore, userCred, USER_TAG_PREFIX)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetAll")
|
||||
}
|
||||
model.GetIStandaloneModel().OnMetadataUpdated(ctx, userCred)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) SetCloudMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||||
return Metadata.SetAll(ctx, model, dictstore, userCred, CLOUD_TAG_PREFIX)
|
||||
err := Metadata.SetAll(ctx, model, dictstore, userCred, CLOUD_TAG_PREFIX)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetAll")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) RemoveMetadata(ctx context.Context, key string, userCred mcclient.TokenCredential) error {
|
||||
return Metadata.SetValue(ctx, model, key, "", userCred)
|
||||
err := Metadata.SetValue(ctx, model, key, "", userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetValue")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) RemoveAllMetadata(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
return Metadata.RemoveAll(ctx, model, userCred)
|
||||
err := Metadata.RemoveAll(ctx, model, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "RemoveAll")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error) {
|
||||
@@ -530,3 +579,7 @@ func (model *SStandaloneResourceBase) ValidateUpdateData(ctx context.Context, us
|
||||
func (model *SStandaloneResourceBase) IsShared() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (model *SStandaloneResourceBase) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ type IUsage interface {
|
||||
var (
|
||||
CancelUsages func(ctx context.Context, userCred mcclient.TokenCredential, usages []IUsage)
|
||||
|
||||
AddUsages func(ctx context.Context, userCred mcclient.TokenCredential, usages []IUsage)
|
||||
|
||||
CancelPendingUsagesInContext func(ctx context.Context, userCred mcclient.TokenCredential) error
|
||||
|
||||
InitPendingUsagesInContext func(ctx context.Context) context.Context
|
||||
|
||||
@@ -449,11 +449,21 @@ func (model *SVirtualResourceBase) AllowPerformCancelDelete(ctx context.Context,
|
||||
func (model *SVirtualResourceBase) PerformCancelDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if model.PendingDeleted && !model.Deleted {
|
||||
err := model.DoCancelPendingDelete(ctx, userCred)
|
||||
return nil, err
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "model.DoCancelPendingDelete")
|
||||
}
|
||||
model.RecoverUsages(ctx, userCred)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (model *SVirtualResourceBase) RecoverUsages(ctx context.Context, userCred mcclient.TokenCredential) {
|
||||
usages := model.GetIModel().GetUsages()
|
||||
if AddUsages != nil && len(usages) > 0 {
|
||||
AddUsages(ctx, userCred, usages)
|
||||
}
|
||||
}
|
||||
|
||||
func (model *SVirtualResourceBase) DoCancelPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
err := model.CancelPendingDelete(ctx, userCred)
|
||||
if err == nil {
|
||||
@@ -472,7 +482,10 @@ func (model *SVirtualResourceBase) GetIVirtualModel() IVirtualModel {
|
||||
|
||||
func (model *SVirtualResourceBase) CancelPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
if model.PendingDeleted && !model.Deleted {
|
||||
return model.MarkCancelPendingDelete(ctx, userCred)
|
||||
err := model.MarkCancelPendingDelete(ctx, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "MarkCancelPendingDelete")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,13 @@
|
||||
|
||||
package notifyclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
)
|
||||
|
||||
const (
|
||||
SYSTEM_ERROR = "SYSTEM_ERROR"
|
||||
SYSTEM_WARNING = "SYSTEM_WARNING"
|
||||
@@ -28,3 +35,42 @@ const (
|
||||
|
||||
IMAGE_ACTIVED = "IMAGE_ACTIVED"
|
||||
)
|
||||
|
||||
type SAction string
|
||||
|
||||
var (
|
||||
Event SEvent
|
||||
|
||||
ActionCreate SAction = "create"
|
||||
ActionUpdate SAction = "update"
|
||||
ActionDelete SAction = "delete"
|
||||
ActionRebuildRoot SAction = "rebuild_root"
|
||||
ActionChangeConfig SAction = "change_config"
|
||||
)
|
||||
|
||||
type SEvent struct {
|
||||
resourceType string
|
||||
action SAction
|
||||
}
|
||||
|
||||
func (se SEvent) WithResourceType(manager db.IModelManager) SEvent {
|
||||
se.resourceType = manager.Keyword()
|
||||
return se
|
||||
}
|
||||
|
||||
func (se SEvent) WithAction(a SAction) SEvent {
|
||||
se.action = a
|
||||
return se
|
||||
}
|
||||
|
||||
func (se SEvent) ResourceType() string {
|
||||
return se.resourceType
|
||||
}
|
||||
|
||||
func (se SEvent) Action() string {
|
||||
return string(se.action)
|
||||
}
|
||||
|
||||
func (se SEvent) String() string {
|
||||
return strings.ToUpper(fmt.Sprintf("%s_%s", se.ResourceType(), se.Action()))
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -29,12 +30,15 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/i18n"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
npk "yunion.io/x/onecloud/pkg/mcclient/modules/notify"
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -97,6 +101,9 @@ func getTemplate(ctx context.Context, topic string, contType string, channel npk
|
||||
}
|
||||
|
||||
func getContent(ctx context.Context, topic string, contType string, channel npk.TNotifyChannel, data jsonutils.JSONObject) (string, error) {
|
||||
if channel == npk.NotifyByWebhook {
|
||||
return "", nil
|
||||
}
|
||||
tmpl, err := getTemplate(ctx, topic, contType, channel)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -110,6 +117,23 @@ func getContent(ctx context.Context, topic string, contType string, channel npk.
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func NotifyWebhook(ctx context.Context, userCred mcclient.TokenCredential, obj db.IModel, action SAction) error {
|
||||
ret, err := db.FetchCustomizeColumns(obj.GetModelManager(), ctx, userCred, jsonutils.NewDict(), []interface{}{obj}, stringutils2.SSortedStrings{}, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ret) == 0 {
|
||||
return fmt.Errorf("unable to get details for model %q", obj.GetId())
|
||||
}
|
||||
event := Event.WithAction(action).WithResourceType(obj.GetModelManager())
|
||||
msg := jsonutils.NewDict()
|
||||
msg.Set("resource_type", jsonutils.NewString(event.ResourceType()))
|
||||
msg.Set("action", jsonutils.NewString(event.Action()))
|
||||
msg.Set("resource_details", ret[0])
|
||||
RawNotifyWithCtx(ctx, []string{}, false, npk.NotifyByWebhook, npk.NotifyPriorityNormal, event.String(), msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func NotifyWithCtx(ctx context.Context, recipientId []string, isGroup bool, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) {
|
||||
notify(ctx, recipientId, isGroup, priority, event, data)
|
||||
}
|
||||
@@ -137,7 +161,16 @@ func RawNotify(recipientId []string, isGroup bool, channel npk.TNotifyChannel, p
|
||||
rawNotify(context.Background(), recipientId, isGroup, channel, priority, event, data)
|
||||
}
|
||||
|
||||
func rawNotify(ctx context.Context, recipientId []string, isGroup bool, channel npk.TNotifyChannel, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) {
|
||||
// IntelliNotify try to create receiver nonexistent if createReceiver is set to true
|
||||
func IntelliNotify(ctx context.Context, recipientId []string, isGroup bool, channel npk.TNotifyChannel, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject, createReceiver bool) {
|
||||
intelliNotify(ctx, recipientId, isGroup, channel, priority, event, data, createReceiver)
|
||||
}
|
||||
|
||||
const noSuchReceiver = `no such receiver whose uid is '(.*)'`
|
||||
|
||||
var noSuchReceiverRegexp = regexp.MustCompile(noSuchReceiver)
|
||||
|
||||
func intelliNotify(ctx context.Context, recipientId []string, isGroup bool, channel npk.TNotifyChannel, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject, createReceiver bool) {
|
||||
log.Infof("notify %s event %s priority %s", recipientId, event, priority)
|
||||
msg := npk.SNotifyMessage{}
|
||||
if isGroup {
|
||||
@@ -160,13 +193,46 @@ func rawNotify(ctx context.Context, recipientId []string, isGroup bool, channel
|
||||
// log.Debugf("send notification %s %s", topic, body)
|
||||
notifyClientWorkerMan.Run(func() {
|
||||
s := auth.GetAdminSession(context.Background(), consts.GetRegion(), "")
|
||||
err := npk.Notifications.Send(s, msg)
|
||||
if err != nil {
|
||||
log.Errorf("unable to send notification: %v", err)
|
||||
for {
|
||||
err := npk.Notifications.Send(s, msg)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if !createReceiver {
|
||||
log.Errorf("unable to send notification: %v", err)
|
||||
break
|
||||
}
|
||||
jerr, ok := err.(*httputils.JSONClientError)
|
||||
if !ok {
|
||||
log.Errorf("unable to send notification: %v", err)
|
||||
break
|
||||
}
|
||||
if jerr.Code > 500 {
|
||||
log.Errorf("unable to send notification: %v", err)
|
||||
break
|
||||
}
|
||||
match := noSuchReceiverRegexp.FindStringSubmatch(jerr.Details)
|
||||
if match == nil || len(match) <= 1 {
|
||||
log.Errorf("unable to send notification: %v", err)
|
||||
break
|
||||
}
|
||||
receiverId := match[1]
|
||||
createData := jsonutils.NewDict()
|
||||
createData.Set("uid", jsonutils.NewString(receiverId))
|
||||
_, err = modules.NotifyReceiver.Create(s, createData)
|
||||
if err != nil {
|
||||
log.Errorf("try to create receiver %q, but failed: %v", receiverId, err)
|
||||
break
|
||||
}
|
||||
log.Infof("create receiver %q successfully", receiverId)
|
||||
}
|
||||
}, nil, nil)
|
||||
}
|
||||
|
||||
func rawNotify(ctx context.Context, recipientId []string, isGroup bool, channel npk.TNotifyChannel, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) {
|
||||
intelliNotify(ctx, recipientId, isGroup, channel, priority, event, data, false)
|
||||
}
|
||||
|
||||
func NotifyNormal(recipientId []string, isGroup bool, event string, data jsonutils.JSONObject) {
|
||||
notifyNormal(context.Background(), recipientId, isGroup, event, data)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ type SCloudaccountCredential struct {
|
||||
// 秘钥key (Aliyun, Aws, huawei, ucloud, ctyun, zstack, s3)
|
||||
AccessKeySecret string `json:"access_key_secret"`
|
||||
|
||||
// 环境 (Azure, Aws, huawei, ctyun)
|
||||
// 环境 (Azure, Aws, huawei, ctyun, aliyun)
|
||||
Environment string `json:"environment"`
|
||||
|
||||
// 目录ID (Azure)
|
||||
|
||||
@@ -317,6 +317,8 @@ type ICloudVM interface {
|
||||
LiveMigrateVM(hostid string) error
|
||||
|
||||
GetError() error
|
||||
|
||||
SetMetadata(tags map[string]string, replace bool) error
|
||||
}
|
||||
|
||||
type ICloudNic interface {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
)
|
||||
|
||||
const DEFAULT_CLOUD_RULE_ID = "default_cloud_rule_id"
|
||||
const DEFAULT_LOCAL_RULE_ID = "default_local_rule_id"
|
||||
|
||||
type SecurityGroupFilterOptions struct {
|
||||
VpcId string
|
||||
@@ -44,6 +45,42 @@ type SecurityRule struct {
|
||||
ExternalId string
|
||||
}
|
||||
|
||||
type LocalSecurityRule struct {
|
||||
secrules.SecurityRule
|
||||
ExternalId string
|
||||
}
|
||||
|
||||
func (r LocalSecurityRule) String() string {
|
||||
return r.SecurityRule.String()
|
||||
}
|
||||
|
||||
type LocalSecurityRuleSet []LocalSecurityRule
|
||||
|
||||
func (srs LocalSecurityRuleSet) Len() int {
|
||||
return len(srs)
|
||||
}
|
||||
|
||||
func (srs LocalSecurityRuleSet) Swap(i, j int) {
|
||||
srs[i], srs[j] = srs[j], srs[i]
|
||||
}
|
||||
|
||||
func (srs LocalSecurityRuleSet) Less(i, j int) bool {
|
||||
if srs[i].Priority > srs[j].Priority {
|
||||
return true
|
||||
} else if srs[i].Priority == srs[j].Priority {
|
||||
return srs[i].String() < srs[j].String()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (srs LocalSecurityRuleSet) AllowList() secrules.SecurityRuleSet {
|
||||
rules := secrules.SecurityRuleSet{}
|
||||
for _, r := range srs {
|
||||
rules = append(rules, r.SecurityRule)
|
||||
}
|
||||
return rules.AllowList()
|
||||
}
|
||||
|
||||
type TPriorityOrder int
|
||||
|
||||
var (
|
||||
@@ -112,13 +149,15 @@ func CompareRules(
|
||||
defaultInRule, defaultOutRule SecurityRule,
|
||||
onlyAllowRules bool, debug bool,
|
||||
) (common, inAdds, outAdds, inDels, outDels []SecurityRule) {
|
||||
localInRules := secrules.SecurityRuleSet{}
|
||||
localOutRules := secrules.SecurityRuleSet{}
|
||||
localInRules := LocalSecurityRuleSet{}
|
||||
localOutRules := LocalSecurityRuleSet{}
|
||||
for i := range localRules {
|
||||
localRule := LocalSecurityRule{}
|
||||
localRule.SecurityRule = localRules[i]
|
||||
if localRules[i].Direction == secrules.DIR_IN {
|
||||
localInRules = append(localInRules, localRules[i])
|
||||
localInRules = append(localInRules, localRule)
|
||||
} else {
|
||||
localOutRules = append(localOutRules, localRules[i])
|
||||
localOutRules = append(localOutRules, localRule)
|
||||
}
|
||||
}
|
||||
inRules := SecurityRuleSet{}
|
||||
@@ -132,17 +171,22 @@ func CompareRules(
|
||||
}
|
||||
var inCommon, outCommon = inRules, outRules
|
||||
|
||||
defaultLocalInRule := *secrules.MustParseSecurityRule("in:deny any")
|
||||
defaultLocalOutRule := *secrules.MustParseSecurityRule("out:allow any")
|
||||
defaultLocalInRule := LocalSecurityRule{ExternalId: DEFAULT_LOCAL_RULE_ID}
|
||||
defaultLocalInRule.SecurityRule = *secrules.MustParseSecurityRule("in:deny any")
|
||||
defaultLocalOutRule := LocalSecurityRule{ExternalId: DEFAULT_LOCAL_RULE_ID}
|
||||
defaultLocalOutRule.SecurityRule = *secrules.MustParseSecurityRule("out:allow any")
|
||||
|
||||
inRules = AddDefaultRule(inRules, defaultInRule, defaultLocalInRule.String(), order, minPriority, maxPriority, onlyAllowRules)
|
||||
outRules = AddDefaultRule(outRules, defaultOutRule, defaultLocalOutRule.String(), order, minPriority, maxPriority, onlyAllowRules)
|
||||
|
||||
defaultInEquals, defaultOutEquals := true, true
|
||||
if defaultLocalInRule.String() != defaultInRule.String() {
|
||||
localInRules = append(localInRules, defaultLocalInRule)
|
||||
defaultInEquals = false
|
||||
}
|
||||
if defaultLocalOutRule.String() != defaultOutRule.String() {
|
||||
localOutRules = append(localOutRules, defaultLocalOutRule)
|
||||
defaultOutEquals = false
|
||||
}
|
||||
|
||||
sort.Sort(localInRules)
|
||||
@@ -150,9 +194,26 @@ func CompareRules(
|
||||
|
||||
localInAllowList := localInRules.AllowList()
|
||||
localOutAllowList := localOutRules.AllowList()
|
||||
_localInRules := LocalSecurityRuleSet{}
|
||||
for i := range localInAllowList {
|
||||
rule := LocalSecurityRule{}
|
||||
rule.SecurityRule = localInAllowList[i]
|
||||
_localInRules = append(_localInRules, rule)
|
||||
}
|
||||
_localOutRules := LocalSecurityRuleSet{}
|
||||
for i := range localOutAllowList {
|
||||
rule := LocalSecurityRule{}
|
||||
rule.SecurityRule = localOutAllowList[i]
|
||||
_localOutRules = append(_localOutRules, rule)
|
||||
}
|
||||
if onlyAllowRules {
|
||||
localInRules = localInAllowList
|
||||
localOutRules = localOutAllowList
|
||||
localOutRules, localInRules = _localOutRules, _localInRules
|
||||
}
|
||||
if len(_localInRules) < len(localInRules) {
|
||||
localInRules = _localInRules
|
||||
}
|
||||
if len(_localOutRules) < len(localOutRules) {
|
||||
localOutRules = _localOutRules
|
||||
}
|
||||
|
||||
SortSecurityRule(inRules, order, onlyAllowRules)
|
||||
@@ -199,7 +260,7 @@ func CompareRules(
|
||||
return init
|
||||
}
|
||||
|
||||
var compare = func(localRules secrules.SecurityRuleSet, remoteRules SecurityRuleSet) (common, add, del []SecurityRule) {
|
||||
var compare = func(localRules LocalSecurityRuleSet, remoteRules SecurityRuleSet) (common, add, del []SecurityRule) {
|
||||
i, j, inc, prePriority := 0, 0, 1, 0
|
||||
for i < len(localRules) || j < len(remoteRules) {
|
||||
if i < len(localRules) && j < len(remoteRules) {
|
||||
@@ -214,7 +275,11 @@ func CompareRules(
|
||||
if remoteRules[j].ExternalId == DEFAULT_CLOUD_RULE_ID {
|
||||
remoteRules[j].Priority = addPriority(remoteRules[j].Priority, order, 1, minPriority, maxPriority, onlyAllowRules)
|
||||
}
|
||||
common = append(common, remoteRules[j])
|
||||
if localRules[i].ExternalId != DEFAULT_LOCAL_RULE_ID ||
|
||||
(localRules[i].Direction == secrules.DIR_IN && !defaultInEquals) ||
|
||||
(localRules[i].Direction == secrules.DIR_OUT && !defaultOutEquals) {
|
||||
common = append(common, remoteRules[j])
|
||||
}
|
||||
i++
|
||||
j++
|
||||
} else if cmp < 0 {
|
||||
@@ -225,7 +290,11 @@ func CompareRules(
|
||||
} else {
|
||||
initPriority := getInitPriority(prePriority, minPriority, maxPriority)
|
||||
localRules[i].Priority = addPriority(initPriority, order, inc, minPriority, maxPriority, onlyAllowRules)
|
||||
add = append(add, SecurityRule{SecurityRule: localRules[i]})
|
||||
if localRules[i].ExternalId != DEFAULT_LOCAL_RULE_ID ||
|
||||
(localRules[i].Direction == secrules.DIR_IN && !defaultInEquals) ||
|
||||
(localRules[i].Direction == secrules.DIR_OUT && !defaultOutEquals) {
|
||||
add = append(add, SecurityRule{SecurityRule: localRules[i].SecurityRule})
|
||||
}
|
||||
i++
|
||||
inc++
|
||||
}
|
||||
@@ -241,7 +310,11 @@ func CompareRules(
|
||||
}
|
||||
initPriority = getInitPriority(initPriority, minPriority, maxPriority) // 若是初始添加规则,尽量以中间为节点,避免仅出现天地规则
|
||||
localRules[i].Priority = addPriority(initPriority, order, inc, minPriority, maxPriority, onlyAllowRules)
|
||||
add = append(add, SecurityRule{SecurityRule: localRules[i]})
|
||||
if localRules[i].ExternalId != DEFAULT_LOCAL_RULE_ID ||
|
||||
(localRules[i].Direction == secrules.DIR_IN && !defaultInEquals) ||
|
||||
(localRules[i].Direction == secrules.DIR_OUT && !defaultOutEquals) {
|
||||
add = append(add, SecurityRule{SecurityRule: localRules[i].SecurityRule})
|
||||
}
|
||||
i++
|
||||
inc++
|
||||
}
|
||||
@@ -250,17 +323,17 @@ func CompareRules(
|
||||
}
|
||||
|
||||
type rulePair struct {
|
||||
localRules []secrules.SecurityRule
|
||||
localRules LocalSecurityRuleSet
|
||||
remoteRules []SecurityRule
|
||||
protocol string
|
||||
}
|
||||
|
||||
var splitRules = func(localRules []secrules.SecurityRule, remoteRules []SecurityRule) []rulePair {
|
||||
var splitRules = func(localRules LocalSecurityRuleSet, remoteRules []SecurityRule) []rulePair {
|
||||
rules := map[string]rulePair{}
|
||||
for _, r := range localRules {
|
||||
pair, ok := rules[r.Protocol]
|
||||
if !ok {
|
||||
pair = rulePair{localRules: []secrules.SecurityRule{}, remoteRules: []SecurityRule{}, protocol: r.Protocol}
|
||||
pair = rulePair{localRules: LocalSecurityRuleSet{}, remoteRules: []SecurityRule{}, protocol: r.Protocol}
|
||||
}
|
||||
pair.localRules = append(pair.localRules, r)
|
||||
rules[r.Protocol] = pair
|
||||
@@ -269,7 +342,7 @@ func CompareRules(
|
||||
for _, r := range remoteRules {
|
||||
pair, ok := rules[r.Protocol]
|
||||
if !ok {
|
||||
pair = rulePair{localRules: []secrules.SecurityRule{}, remoteRules: []SecurityRule{}, protocol: r.Protocol}
|
||||
pair = rulePair{localRules: LocalSecurityRuleSet{}, remoteRules: []SecurityRule{}, protocol: r.Protocol}
|
||||
}
|
||||
pair.remoteRules = append(pair.remoteRules, r)
|
||||
rules[r.Protocol] = pair
|
||||
@@ -282,7 +355,7 @@ func CompareRules(
|
||||
return ret
|
||||
}
|
||||
|
||||
var compareRules = func(localRules []secrules.SecurityRule, remoteRules []SecurityRule) (common, add, dels []SecurityRule) {
|
||||
var compareRules = func(localRules LocalSecurityRuleSet, remoteRules []SecurityRule) (common, add, dels []SecurityRule) {
|
||||
pairs := splitRules(localRules, remoteRules)
|
||||
for _, r := range pairs {
|
||||
_common, _add, _dels := compare(r.localRules, r.remoteRules)
|
||||
|
||||
@@ -77,8 +77,8 @@ func (self *SAliyunGuestDriver) GetStorageTypes() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SAliyunGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SAliyunGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SAliyunGuestDriver) GetDetachDiskStatus() ([]string, error) {
|
||||
|
||||
@@ -131,8 +131,8 @@ func (self *SAwsGuestDriver) GetStorageTypes() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SAwsGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SAwsGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SAwsGuestDriver) GetDetachDiskStatus() ([]string, error) {
|
||||
|
||||
@@ -79,8 +79,8 @@ func (self *SAzureGuestDriver) GetStorageTypes() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SAzureGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SAzureGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SAzureGuestDriver) GetMaxSecurityGroupCount() int {
|
||||
|
||||
@@ -249,15 +249,15 @@ func (self *SBaremetalGuestDriver) GetStorageTypes() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
func (self *SBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
if len(storageIds) != 0 {
|
||||
return models.StorageManager.FetchStorageById(storageIds[0])
|
||||
return models.StorageManager.FetchStorageById(storageIds[0]), nil
|
||||
}
|
||||
bs := host.GetBaremetalstorage()
|
||||
if bs == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
return bs.GetStorage()
|
||||
return bs.GetStorage(), nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalGuestDriver) RequestGuestCreateAllDisks(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
|
||||
|
||||
@@ -393,3 +393,8 @@ func (self *SBaseGuestDriver) RequestMigrate(ctx context.Context, guest *models.
|
||||
func (self *SBaseGuestDriver) RequestLiveMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error {
|
||||
return fmt.Errorf("Not Implement RequestLiveMigrate")
|
||||
}
|
||||
|
||||
func (self *SBaseGuestDriver) RequestRemoteUpdate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, replaceTags bool) error {
|
||||
// nil ops
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -79,6 +79,46 @@ func (self *SESXiGuestDriver) GetDefaultSysDiskBackend() string {
|
||||
return api.STORAGE_LOCAL
|
||||
}
|
||||
|
||||
func (self *SESXiGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
if !options.Options.LockStorageFromCachedimage || len(diskConfig.ImageId) == 0 {
|
||||
return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds)
|
||||
}
|
||||
var (
|
||||
image *cloudprovider.SImage
|
||||
err error
|
||||
)
|
||||
obj, err := models.CachedimageManager.FetchById(diskConfig.ImageId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to fetch cachedimage %s", diskConfig.ImageId)
|
||||
}
|
||||
cachedimage := obj.(*models.SCachedimage)
|
||||
if len(cachedimage.ExternalId) > 0 || cachedimage.ImageType != cloudprovider.CachedImageTypeSystem {
|
||||
return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds)
|
||||
}
|
||||
storages, err := cachedimage.GetStorages()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to GetStorages of cachedimage %s", diskConfig.ImageId)
|
||||
}
|
||||
if len(storages) == 0 {
|
||||
log.Warningf("there no storage associated with cachedimage %q", image.Id)
|
||||
return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds)
|
||||
}
|
||||
if len(storages) > 1 {
|
||||
log.Warningf("there are multiple storageCache associated with caheimage %q", image.Id)
|
||||
}
|
||||
wantStorageIds := make([]string, len(storages))
|
||||
for i := range wantStorageIds {
|
||||
wantStorageIds[i] = storages[i].GetId()
|
||||
}
|
||||
for i := range wantStorageIds {
|
||||
if utils.IsInStringArray(wantStorageIds[i], storageIds) {
|
||||
log.Infof("use storage %q in where cachedimage %q", wantStorageIds[i], image.Id)
|
||||
return &storages[i], nil
|
||||
}
|
||||
}
|
||||
return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds)
|
||||
}
|
||||
|
||||
func (self *SESXiGuestDriver) GetMinimalSysDiskSizeGb() int {
|
||||
return options.Options.DefaultDiskSizeMB / 1024
|
||||
}
|
||||
@@ -183,16 +223,34 @@ func (self *SESXiGuestDriver) GetJsonDescAtHost(ctx context.Context, userCred mc
|
||||
return desc, errors.Errorf("no such storage cache associated with cacheimage %s", templateId)
|
||||
}
|
||||
if len(storageCaches) > 1 {
|
||||
return desc, errors.Errorf("there are multiple storageCache associated with caheimage '%s' ??!!", templateId)
|
||||
log.Warningf("there are multiple storageCache associated with caheimage '%s' ??!!", templateId)
|
||||
}
|
||||
|
||||
var hostIp string
|
||||
storageCacheHost, err := storageCaches[0].GetHost()
|
||||
if err != nil {
|
||||
log.Errorf("fail to GetHost of storageCache %s", storageCaches[0].Id)
|
||||
hostIp = storageCaches[0].ExternalId
|
||||
var storageCacheHost *models.SHost
|
||||
// select storagecacheHost
|
||||
for i := range storageCaches {
|
||||
hosts, err := storageCaches[i].GetHosts()
|
||||
if err != nil {
|
||||
return desc, errors.Wrap(err, "storageCaches.GetHosts")
|
||||
}
|
||||
for i := range hosts {
|
||||
if host.GetId() == hosts[i].GetId() {
|
||||
storageCacheHost = &hosts[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
hostIp = storageCacheHost.AccessIp
|
||||
|
||||
if storageCacheHost == nil {
|
||||
storageCacheHost, err = storageCaches[0].GetHost()
|
||||
if err != nil {
|
||||
return desc, errors.Wrapf(err, "unable to GetHost of storageCache %s", storageCaches[0].Id)
|
||||
}
|
||||
if storageCacheHost == nil {
|
||||
return desc, fmt.Errorf("unable to GetHost of storageCache %s: result is nil", storageCaches[0].Id)
|
||||
}
|
||||
}
|
||||
|
||||
hostIp := storageCacheHost.AccessIp
|
||||
imageInfo := SEsxiImageInfo{
|
||||
ImageType: img.ImageType,
|
||||
ImageExternalId: img.ExternalId,
|
||||
|
||||
@@ -77,12 +77,13 @@ func (self *SGoogleGuestDriver) GetStorageTypes() []string {
|
||||
return []string{
|
||||
api.STORAGE_GOOGLE_PD_SSD,
|
||||
api.STORAGE_GOOGLE_PD_STANDARD,
|
||||
api.STORAGE_GOOGLE_PD_BALANCED,
|
||||
api.STORAGE_GOOGLE_LOCAL_SSD,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SGoogleGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SGoogleGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SGoogleGuestDriver) GetGuestInitialStateAfterCreate() string {
|
||||
@@ -113,7 +114,7 @@ func (self *SGoogleGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *m
|
||||
if !utils.IsInStringArray(guest.Status, []string{api.VM_READY, api.VM_RUNNING}) {
|
||||
return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status)
|
||||
}
|
||||
if !utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_PD_STANDARD}) {
|
||||
if !utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_BALANCED}) {
|
||||
return fmt.Errorf("Cannot resize %s disk", storage.StorageType)
|
||||
}
|
||||
return nil
|
||||
@@ -132,13 +133,15 @@ func (self *SGoogleGuestDriver) ValidateCreateData(ctx context.Context, userCred
|
||||
minGB := -1
|
||||
maxGB := -1
|
||||
switch disk.Backend {
|
||||
case api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_PD_STANDARD:
|
||||
case api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_BALANCED:
|
||||
minGB = 10
|
||||
maxGB = 65536
|
||||
case api.STORAGE_GOOGLE_LOCAL_SSD:
|
||||
minGB = 375
|
||||
maxGB = 375
|
||||
localDisk++
|
||||
default:
|
||||
return nil, httperrors.NewInputParameterError("Unknown google storage type %s", disk.Backend)
|
||||
}
|
||||
if i == 0 && disk.Backend == api.STORAGE_GOOGLE_LOCAL_SSD {
|
||||
return nil, httperrors.NewInputParameterError("System disk does not support %s disk", disk.Backend)
|
||||
|
||||
@@ -67,8 +67,8 @@ func (self *SHuaweiGuestDriver) GetStorageTypes() []string {
|
||||
return []string{api.STORAGE_HUAWEI_SATA, api.STORAGE_HUAWEI_SAS, api.STORAGE_HUAWEI_SSD}
|
||||
}
|
||||
|
||||
func (self *SHuaweiGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SHuaweiGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiGuestDriver) GetDetachDiskStatus() ([]string, error) {
|
||||
|
||||
@@ -1215,3 +1215,30 @@ func (self *SManagedVirtualizedGuestDriver) RequestSetAutoRenewInstance(ctx cont
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SManagedVirtualizedGuestDriver) RequestRemoteUpdate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, replaceTags bool) error {
|
||||
// nil ops
|
||||
iVM, err := guest.GetIVM()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "guest.GetIVM")
|
||||
}
|
||||
tags, err := guest.GetAllUserMetadata()
|
||||
if err != nil {
|
||||
log.Errorf("GetAllUserMetadata fail %s", err)
|
||||
} else {
|
||||
err := iVM.SetMetadata(tags, replaceTags)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "iVM.SetMetadata")
|
||||
}
|
||||
// sync back cloud metadata
|
||||
err = models.SyncVirtualResourceMetadata(ctx, userCred, guest, iVM)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "syncVirtualResourceMetadata")
|
||||
}
|
||||
}
|
||||
err = iVM.UpdateVM(ctx, guest.Name)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "iVM.UpdateVM")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ func (self *SOpenStackGuestDriver) GetStorageTypes() []string {
|
||||
return storages
|
||||
}
|
||||
|
||||
func (self *SOpenStackGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SOpenStackGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SOpenStackGuestDriver) GetDetachDiskStatus() ([]string, error) {
|
||||
|
||||
@@ -75,8 +75,8 @@ func (self *SQcloudGuestDriver) GetStorageTypes() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SQcloudGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SQcloudGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SQcloudGuestDriver) GetDetachDiskStatus() ([]string, error) {
|
||||
|
||||
@@ -174,11 +174,11 @@ func (self *SVirtualizedGuestDriver) GetStorageTypes() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
if len(storageIds) == 0 {
|
||||
return host.GetLeastUsedStorage(backend)
|
||||
return host.GetLeastUsedStorage(diskConfig.Backend), nil
|
||||
}
|
||||
return models.StorageManager.FetchStorageById(storageIds[0])
|
||||
return models.StorageManager.FetchStorageById(storageIds[0]), nil
|
||||
}
|
||||
|
||||
func (self *SVirtualizedGuestDriver) RequestGuestCreateInsertIso(ctx context.Context, imageId string, guest *models.SGuest, task taskman.ITask) error {
|
||||
|
||||
@@ -85,8 +85,8 @@ func (self *SZStackGuestDriver) GetMaxSecurityGroupCount() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (self *SZStackGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
|
||||
return self.chooseHostStorage(self, host, backend, storageIds)
|
||||
func (self *SZStackGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
|
||||
return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
|
||||
}
|
||||
|
||||
func (self *SZStackGuestDriver) GetDetachDiskStatus() ([]string, error) {
|
||||
|
||||
@@ -48,7 +48,7 @@ func (self *SGoogleHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb
|
||||
minGB := 10
|
||||
maxGB := -1
|
||||
switch storage.StorageType {
|
||||
case api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_PD_STANDARD:
|
||||
case api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_BALANCED:
|
||||
maxGB = 65536
|
||||
default:
|
||||
return fmt.Errorf("Not support resize %s disk", storage.StorageType)
|
||||
|
||||
@@ -272,6 +272,18 @@ func (manager *SCachedimageManager) cacheGlanceImageInfo(ctx context.Context, us
|
||||
}
|
||||
}
|
||||
|
||||
func (image *SCachedimage) GetStorages() ([]SStorage, error) {
|
||||
sq := StorageManager.Query()
|
||||
storagecacheimageSubq := StoragecachedimageManager.Query("storagecache_id").Equals("cachedimage_id", image.GetId()).SubQuery()
|
||||
sq.Join(storagecacheimageSubq, sqlchemy.Equals(sq.Field("storagecache_id"), storagecacheimageSubq.Field("storagecache_id")))
|
||||
storages := make([]SStorage, 0, 1)
|
||||
err := db.FetchModelObjects(StorageManager, sq, &storages)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "FetchModelObjects")
|
||||
}
|
||||
return storages, nil
|
||||
}
|
||||
|
||||
func (manager *SCachedimageManager) GetImageById(ctx context.Context, userCred mcclient.TokenCredential, imageId string, refresh bool) (*cloudprovider.SImage, error) {
|
||||
imgObj, _ := manager.FetchById(imageId)
|
||||
if imgObj != nil {
|
||||
@@ -472,7 +484,11 @@ func (self *SCachedimage) canDeleteLastCache() bool {
|
||||
|
||||
func (self *SCachedimage) syncWithCloudImage(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, image cloudprovider.ICloudImage, managerId string) error {
|
||||
diff, err := db.UpdateWithLock(ctx, self, func() error {
|
||||
self.Name = image.GetName()
|
||||
newName, err := db.GenerateAlterName(self, image.GetName())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GenerateAlterName")
|
||||
}
|
||||
self.Name = newName
|
||||
self.Size = image.GetSizeByte()
|
||||
self.ExternalId = image.GetGlobalId()
|
||||
self.ImageType = image.GetImageType()
|
||||
@@ -668,20 +684,6 @@ func (manager *SCachedimageManager) ListItemFilter(
|
||||
return nil, errors.Wrapf(err, "SSharableBaseResourceManager.ListItemFilter")
|
||||
}
|
||||
|
||||
q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "id", func() *sqlchemy.SQuery {
|
||||
cachedImages := CachedimageManager.Query().SubQuery()
|
||||
storagecachedImages := StoragecachedimageManager.Query().SubQuery()
|
||||
storageCaches := StoragecacheManager.Query().SubQuery()
|
||||
|
||||
subq := cachedImages.Query(cachedImages.Field("id"))
|
||||
subq = subq.Join(storagecachedImages, sqlchemy.Equals(cachedImages.Field("id"), storagecachedImages.Field("cachedimage_id")))
|
||||
subq = subq.Join(storageCaches, sqlchemy.Equals(storagecachedImages.Field("storagecache_id"), storageCaches.Field("id")))
|
||||
return subq
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "managedResourceFilterByAccount")
|
||||
}
|
||||
|
||||
q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter")
|
||||
@@ -692,59 +694,74 @@ func (manager *SCachedimageManager) ListItemFilter(
|
||||
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
|
||||
}
|
||||
|
||||
q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "id", func() *sqlchemy.SQuery {
|
||||
{
|
||||
var idFilter bool
|
||||
storagecachedImages := StoragecachedimageManager.Query().SubQuery()
|
||||
storageCaches := StoragecacheManager.Query().SubQuery()
|
||||
storages := StorageManager.Query().SubQuery()
|
||||
var storages *sqlchemy.SSubQuery
|
||||
|
||||
if query.Valid == nil {
|
||||
storages = StorageManager.Query().SubQuery()
|
||||
} else if *query.Valid {
|
||||
idFilter = true
|
||||
storages = StorageManager.Query().In("status", []string{api.STORAGE_ENABLED, api.STORAGE_ONLINE}).IsTrue("enabled").SubQuery()
|
||||
} else {
|
||||
idFilter = true
|
||||
stroage := StorageManager.Query()
|
||||
storages = stroage.Filter(sqlchemy.OR(sqlchemy.NotIn(stroage.Field("status"), []string{}), sqlchemy.IsFalse(stroage.Field("enabled")))).SubQuery()
|
||||
}
|
||||
zones := ZoneManager.Query().SubQuery()
|
||||
|
||||
subq := storagecachedImages.Query(storagecachedImages.Field("cachedimage_id"))
|
||||
subq = subq.Join(storageCaches, sqlchemy.Equals(storagecachedImages.Field("storagecache_id"), storageCaches.Field("id")))
|
||||
subq = subq.Join(storages, sqlchemy.Equals(storageCaches.Field("id"), storages.Field("storagecache_id")))
|
||||
subq = subq.Join(zones, sqlchemy.Equals(storages.Field("zone_id"), zones.Field("id")))
|
||||
subq = subq.Filter(sqlchemy.Equals(storagecachedImages.Field("status"), api.CACHED_IMAGE_STATUS_ACTIVE))
|
||||
return subq
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "managedResourceFilterByRegion")
|
||||
}
|
||||
|
||||
q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "id", func() *sqlchemy.SQuery {
|
||||
storagecachedImages := StoragecachedimageManager.Query().SubQuery()
|
||||
storageCaches := StoragecacheManager.Query().SubQuery()
|
||||
storages := StorageManager.Query().SubQuery()
|
||||
|
||||
subq := storagecachedImages.Query(storagecachedImages.Field("cachedimage_id"))
|
||||
subq = subq.Join(storageCaches, sqlchemy.Equals(storagecachedImages.Field("storagecache_id"), storageCaches.Field("id")))
|
||||
subq = subq.Join(storages, sqlchemy.Equals(storageCaches.Field("id"), storages.Field("storagecache_id")))
|
||||
if len(query.HostSchedtagId) > 0 {
|
||||
idFilter = true
|
||||
schedTagObj, err := SchedtagManager.FetchByIdOrName(userCred, query.HostSchedtagId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", SchedtagManager.Keyword(), query.HostSchedtagId)
|
||||
} else {
|
||||
return nil, errors.Wrap(err, "SchedtagManager.FetchByIdOrName")
|
||||
}
|
||||
}
|
||||
hoststorages := HoststorageManager.Query("host_id", "storage_id").SubQuery()
|
||||
hostschedtags := HostschedtagManager.Query().Equals("schedtag_id", schedTagObj.GetId()).SubQuery()
|
||||
subq = subq.Join(hoststorages, sqlchemy.Equals(hoststorages.Field("storage_id"), storages.Field("id")))
|
||||
subq = subq.Join(hostschedtags, sqlchemy.Equals(hostschedtags.Field("host_id"), hoststorages.Field("host_id")))
|
||||
}
|
||||
subq = subq.Filter(sqlchemy.Equals(storagecachedImages.Field("status"), api.CACHED_IMAGE_STATUS_ACTIVE))
|
||||
return subq
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "managedResourceFilterByZone")
|
||||
|
||||
subq = subq.Snapshot()
|
||||
|
||||
subq, err = managedResourceFilterByAccount(subq, query.ManagedResourceListInput, "", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "managedResourceFilterByAccount")
|
||||
}
|
||||
|
||||
subq, err = managedResourceFilterByRegion(subq, query.RegionalFilterListInput, "", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "_managedResourceFilterByRegion")
|
||||
}
|
||||
|
||||
subq, err = managedResourceFilterByZone(subq, query.ZonalFilterListInput, "", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "_managedResourceFilterByZone")
|
||||
}
|
||||
|
||||
if subq.IsAltered() {
|
||||
idFilter = true
|
||||
}
|
||||
|
||||
if idFilter {
|
||||
q = q.In("id", subq)
|
||||
}
|
||||
}
|
||||
|
||||
if len(query.ImageType) > 0 {
|
||||
q = q.In("image_type", query.ImageType)
|
||||
}
|
||||
|
||||
if len(query.HostSchedtagId) > 0 {
|
||||
schedTagObj, err := SchedtagManager.FetchByIdOrName(userCred, query.HostSchedtagId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", SchedtagManager.Keyword(), query.HostSchedtagId)
|
||||
} else {
|
||||
return nil, errors.Wrap(err, "SchedtagManager.FetchByIdOrName")
|
||||
}
|
||||
}
|
||||
subq := StoragecachedimageManager.Query("cachedimage_id")
|
||||
storages := StorageManager.Query("id", "storagecache_id").SubQuery()
|
||||
hoststorages := HoststorageManager.Query("host_id", "storage_id").SubQuery()
|
||||
hostschedtags := HostschedtagManager.Query().Equals("schedtag_id", schedTagObj.GetId()).SubQuery()
|
||||
subq = subq.Join(storages, sqlchemy.Equals(storages.Field("storagecache_id"), subq.Field("storagecache_id")))
|
||||
subq = subq.Join(hoststorages, sqlchemy.Equals(hoststorages.Field("storage_id"), storages.Field("id")))
|
||||
subq = subq.Join(hostschedtags, sqlchemy.Equals(hostschedtags.Field("host_id"), hoststorages.Field("host_id")))
|
||||
q = q.In("id", subq.SubQuery())
|
||||
q = q.Equals("image_type", query.ImageType)
|
||||
}
|
||||
|
||||
return q, nil
|
||||
|
||||
@@ -118,6 +118,22 @@ func (self *SCloudregion) ValidateDeleteCondition(ctx context.Context) error {
|
||||
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
|
||||
}
|
||||
|
||||
func (self *SCloudregion) GetElasticIps(managerId, eipMode string) ([]SElasticip, error) {
|
||||
q := ElasticipManager.Query().Equals("cloudregion_id", self.Id)
|
||||
if len(managerId) > 0 {
|
||||
q = q.Equals("manager_id", managerId)
|
||||
}
|
||||
if len(eipMode) > 0 {
|
||||
q = q.Equals("mode", eipMode)
|
||||
}
|
||||
eips := []SElasticip{}
|
||||
err := db.FetchModelObjects(ElasticipManager, q, &eips)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "db.FetchModelObjects")
|
||||
}
|
||||
return eips, nil
|
||||
}
|
||||
|
||||
func (self *SCloudregion) GetZoneQuery() *sqlchemy.SQuery {
|
||||
zones := ZoneManager.Query()
|
||||
if self.Id == api.DEFAULT_REGION_ID {
|
||||
@@ -464,6 +480,7 @@ func (self *SCloudregion) syncWithCloudRegion(ctx context.Context, userCred mccl
|
||||
self.SGeographicInfo = cloudRegion.GetGeographicInfo()
|
||||
self.Provider = cloudRegion.GetProvider()
|
||||
self.Environment = cloudRegion.GetCloudEnv()
|
||||
self.SetEnabled(true)
|
||||
|
||||
self.IsEmulated = cloudRegion.IsEmulated()
|
||||
|
||||
|
||||
@@ -164,6 +164,9 @@ func (manager *SDBInstanceSkuManager) ListItemFilter(
|
||||
if len(query.EngineVersion) > 0 {
|
||||
q = q.In("engine_version", query.EngineVersion)
|
||||
}
|
||||
if len(query.Providers) > 0 {
|
||||
q = q.In("provider", query.Providers)
|
||||
}
|
||||
|
||||
for k, zoneIds := range map[string][]string{"zone1": query.Zone1, "zone2": query.Zone2, "zone3": query.Zone3} {
|
||||
ids := []string{}
|
||||
|
||||
@@ -1536,7 +1536,9 @@ func (self *SDBInstance) SyncWithCloudDBInstance(ctx context.Context, userCred m
|
||||
|
||||
if factory.IsSupportPrepaidResources() {
|
||||
self.BillingType = extInstance.GetBillingType()
|
||||
self.ExpiredAt = extInstance.GetExpiredAt()
|
||||
if expired := extInstance.GetExpiredAt(); !expired.IsZero() {
|
||||
self.ExpiredAt = expired
|
||||
}
|
||||
self.AutoRenew = extInstance.IsAutoRenew()
|
||||
}
|
||||
|
||||
@@ -1626,7 +1628,9 @@ func (manager *SDBInstanceManager) newFromCloudDBInstance(ctx context.Context, u
|
||||
|
||||
if factory.IsSupportPrepaidResources() {
|
||||
instance.BillingType = extInstance.GetBillingType()
|
||||
instance.ExpiredAt = extInstance.GetExpiredAt()
|
||||
if expired := extInstance.GetExpiredAt(); !expired.IsZero() {
|
||||
instance.ExpiredAt = expired
|
||||
}
|
||||
instance.AutoRenew = extInstance.IsAutoRenew()
|
||||
}
|
||||
|
||||
@@ -1642,17 +1646,31 @@ func (manager *SDBInstanceManager) newFromCloudDBInstance(ctx context.Context, u
|
||||
return &instance, nil
|
||||
}
|
||||
|
||||
type SRdsCountStat struct {
|
||||
TotalRdsCount int
|
||||
TotalCpuCount int
|
||||
TotalMemSizeMb int
|
||||
}
|
||||
|
||||
func (man *SDBInstanceManager) TotalCount(
|
||||
scope rbacutils.TRbacScope,
|
||||
ownerId mcclient.IIdentityProvider,
|
||||
rangeObjs []db.IStandaloneModel,
|
||||
providers []string, brands []string, cloudEnv string,
|
||||
) (int, error) {
|
||||
q := man.Query()
|
||||
) (SRdsCountStat, error) {
|
||||
sq := man.Query().SubQuery()
|
||||
q := sq.Query(sqlchemy.COUNT("total_rds_count"),
|
||||
sqlchemy.SUM("total_cpu_count", sq.Field("vcpu_count")),
|
||||
sqlchemy.SUM("total_mem_size_mb", sq.Field("vmem_size_mb")))
|
||||
|
||||
q = scopeOwnerIdFilter(q, scope, ownerId)
|
||||
q = CloudProviderFilter(q, q.Field("manager_id"), providers, brands, cloudEnv)
|
||||
q = RangeObjectsFilter(q, rangeObjs, q.Field("cloudregion_id"), nil, q.Field("manager_id"), nil, nil)
|
||||
return q.CountWithError()
|
||||
|
||||
stat := SRdsCountStat{}
|
||||
row := q.Row()
|
||||
err := q.Row2Struct(row, &stat)
|
||||
return stat, err
|
||||
}
|
||||
|
||||
func (dbinstance *SDBInstance) GetQuotaKeys() quotas.IQuotaKeys {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/compare"
|
||||
"yunion.io/x/pkg/util/fileutils"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
@@ -1542,7 +1543,9 @@ func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mccl
|
||||
|
||||
if provider.GetFactory().IsSupportPrepaidResources() {
|
||||
disk.BillingType = extDisk.GetBillingType()
|
||||
disk.ExpiredAt = extDisk.GetExpiredAt()
|
||||
if expired := extDisk.GetExpiredAt(); !expired.IsZero() {
|
||||
disk.ExpiredAt = expired
|
||||
}
|
||||
disk.AutoRenew = extDisk.IsAutoRenew()
|
||||
}
|
||||
|
||||
@@ -2147,9 +2150,12 @@ func (self *SDisk) AllowPerformCancelDelete(ctx context.Context, userCred mcclie
|
||||
}
|
||||
|
||||
func (self *SDisk) PerformCancelDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if self.PendingDeleted {
|
||||
if self.PendingDeleted && !self.Deleted {
|
||||
err := self.DoCancelPendingDelete(ctx, userCred)
|
||||
return nil, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
self.RecoverUsages(ctx, userCred)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -2448,31 +2454,71 @@ func (self *SDisk) UpdataSnapshotsBackingDisk(backingDiskId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SDiskManager) AutoSyncExtDiskSnapshot(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
isStart bool) {
|
||||
func (manager *SDiskManager) AutoSyncExtDiskSnapshot(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
|
||||
|
||||
spds, err := manager.getAutoSnapshotDisksId(true)
|
||||
if err != nil {
|
||||
log.Errorf("Get auto snapshot ext disks id failed: %s", err)
|
||||
return
|
||||
now := time.Now()
|
||||
week := now.Weekday()
|
||||
if week == 0 {
|
||||
week += 7
|
||||
}
|
||||
if len(spds) == 0 {
|
||||
log.Infof("CronJob AutoSyncExtDiskSnapshot: No external disk need sync snapshot")
|
||||
return
|
||||
timePoint := now.Hour()
|
||||
|
||||
q := SnapshotPolicyDiskManager.Query().LE("next_sync_time", now)
|
||||
spds := make([]SSnapshotPolicyDisk, 0)
|
||||
err := db.FetchModelObjects(SnapshotPolicyDiskManager, q, &spds)
|
||||
if err != nil {
|
||||
log.Errorf("unable to FetchModelObjects: %v", err)
|
||||
}
|
||||
// fetch all snapshotpolicy
|
||||
spIdSet := sets.NewString()
|
||||
for i := range spds {
|
||||
spIdSet.Insert(spds[i].SnapshotpolicyId)
|
||||
}
|
||||
sps, err := SnapshotPolicyManager.FetchAllByIds(spIdSet.UnsortedList())
|
||||
if err != nil {
|
||||
log.Errorf("unable to FetchAllByIds: %v", err)
|
||||
}
|
||||
spMap := make(map[string]*SSnapshotPolicy, len(sps))
|
||||
for i := range sps {
|
||||
spMap[sps[i].GetId()] = &sps[i]
|
||||
}
|
||||
|
||||
for i := 0; i < len(spds); i++ {
|
||||
disk := manager.FetchDiskById(spds[i].DiskId)
|
||||
spd := &spds[i]
|
||||
disk := manager.FetchDiskById(spd.DiskId)
|
||||
|
||||
syncResult := disk.syncSnapshots(ctx, userCred)
|
||||
if syncResult.IsError() {
|
||||
db.OpsLog.LogEvent(disk, db.ACT_DISK_AUTO_SYNC_SNAPSHOT_FAIL, syncResult.Result(), userCred)
|
||||
continue
|
||||
}
|
||||
sp := spMap[spd.GetId()]
|
||||
repeatWeekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(sp.RepeatWeekdays)
|
||||
timePoints := SnapshotPolicyManager.TimePointsToIntArray(sp.TimePoints)
|
||||
if isInInts(int(week), repeatWeekdays) && isInInts(timePoint, timePoints) && syncResult.AddCnt == 0 {
|
||||
// should add one
|
||||
continue
|
||||
}
|
||||
db.OpsLog.LogEvent(disk, db.ACT_DISK_AUTO_SYNC_SNAPSHOT, "disk auto sync snapshot successfully", userCred)
|
||||
_, err := db.Update(spd, func() error {
|
||||
spd.NextSyncTime = spMap[spd.GetId()].ComputeNextSyncTime(now, spd.NextSyncTime)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("unable to update NextSyncTime for snapshotpolicydisk %q %q", spd.SnapshotpolicyId, spd.DiskId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isInInts(a int, array []int) bool {
|
||||
for _, i := range array {
|
||||
if i == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SDisk) syncSnapshots(ctx context.Context, userCred mcclient.TokenCredential) compare.SyncResult {
|
||||
syncResult := compare.SyncResult{}
|
||||
|
||||
|
||||
@@ -649,7 +649,9 @@ func (manager *SElasticcacheManager) newFromCloudElasticcache(ctx context.Contex
|
||||
|
||||
if factory.IsSupportPrepaidResources() {
|
||||
instance.BillingType = extInstance.GetBillingType()
|
||||
instance.ExpiredAt = extInstance.GetExpiredAt()
|
||||
if expired := extInstance.GetExpiredAt(); !expired.IsZero() {
|
||||
instance.ExpiredAt = expired
|
||||
}
|
||||
instance.AutoRenew = extInstance.IsAutoRenew()
|
||||
}
|
||||
|
||||
|
||||
@@ -248,19 +248,6 @@ func (manager *SElasticipManager) QueryDistinctExtraField(q *sqlchemy.SQuery, fi
|
||||
return q, httperrors.ErrNotFound
|
||||
}
|
||||
|
||||
func (manager *SElasticipManager) getEipsByRegion(region *SCloudregion, provider *SCloudprovider) ([]SElasticip, error) {
|
||||
eips := make([]SElasticip, 0)
|
||||
q := manager.Query().Equals("cloudregion_id", region.Id)
|
||||
if provider != nil {
|
||||
q = q.Equals("manager_id", provider.Id)
|
||||
}
|
||||
err := db.FetchModelObjects(manager, q, &eips)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eips, nil
|
||||
}
|
||||
|
||||
func (self *SElasticip) GetRegion() *SCloudregion {
|
||||
return CloudregionManager.FetchRegionById(self.CloudregionId)
|
||||
}
|
||||
@@ -329,7 +316,7 @@ func (manager *SElasticipManager) SyncEips(ctx context.Context, userCred mcclien
|
||||
// remoteEips := make([]cloudprovider.ICloudEIP, 0)
|
||||
syncResult := compare.SyncResult{}
|
||||
|
||||
dbEips, err := manager.getEipsByRegion(region, provider)
|
||||
dbEips, err := region.GetElasticIps(provider.Id, api.EIP_MODE_STANDALONE_EIP)
|
||||
if err != nil {
|
||||
syncResult.Error(err)
|
||||
return syncResult
|
||||
@@ -478,7 +465,9 @@ func (self *SElasticip) SyncWithCloudEip(ctx context.Context, userCred mcclient.
|
||||
factory, _ := provider.GetProviderFactory()
|
||||
if factory != nil && factory.IsSupportPrepaidResources() {
|
||||
self.BillingType = ext.GetBillingType()
|
||||
self.ExpiredAt = ext.GetExpiredAt()
|
||||
if expired := ext.GetExpiredAt(); !expired.IsZero() {
|
||||
self.ExpiredAt = expired
|
||||
}
|
||||
self.AutoRenew = ext.IsAutoRenew()
|
||||
}
|
||||
|
||||
|
||||
@@ -2638,9 +2638,12 @@ func (model *SGuest) AllowPerformCancelDelete(ctx context.Context, userCred mccl
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformCancelDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if self.PendingDeleted {
|
||||
if self.PendingDeleted && !self.Deleted {
|
||||
err := self.DoCancelPendingDelete(ctx, userCred)
|
||||
return nil, err
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DoCancelPendingDelete")
|
||||
}
|
||||
self.RecoverUsages(ctx, userCred)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -3794,7 +3797,7 @@ func (self *SGuest) AllowPerformStreamDisksComplete(ctx context.Context, userCre
|
||||
func (self *SGuest) PerformStreamDisksComplete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
for _, disk := range self.GetDisks() {
|
||||
d := disk.GetDisk()
|
||||
if len(d.SnapshotId) > 0 {
|
||||
if len(d.SnapshotId) > 0 && d.GetMetadata("merge_snapshot", userCred) == "true" {
|
||||
SnapshotManager.AddRefCount(d.SnapshotId, -1)
|
||||
d.SetMetadata(ctx, "merge_snapshot", jsonutils.JSONFalse, userCred)
|
||||
}
|
||||
@@ -5055,3 +5058,15 @@ func (self *SGuest) StartSetAutoRenewTask(ctx context.Context, userCred mcclient
|
||||
task.ScheduleRun(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SGuest) AllowPerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "remote-update")
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerRemoteUpdateInput) (jsonutils.JSONObject, error) {
|
||||
err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "StartRemoteUpdateTask")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ type IGuestDriver interface {
|
||||
GetRandomNetworkTypes() []string
|
||||
|
||||
GetStorageTypes() []string
|
||||
ChooseHostStorage(host *SHost, backend string, storageIds []string) *SStorage
|
||||
ChooseHostStorage(host *SHost, diskConfig *api.DiskConfig, storageIds []string) (*SStorage, error)
|
||||
|
||||
StartGuestCreateTask(guest *SGuest, ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, pendingUsage quotas.IQuota, parentTaskId string) error
|
||||
|
||||
@@ -199,6 +199,8 @@ type IGuestDriver interface {
|
||||
CheckLiveMigrate(guest *SGuest, userCred mcclient.TokenCredential, input api.GuestLiveMigrateInput) error
|
||||
RequestMigrate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error
|
||||
RequestLiveMigrate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error
|
||||
|
||||
RequestRemoteUpdate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, replaceTags bool) error
|
||||
}
|
||||
|
||||
var guestDrivers map[string]IGuestDriver
|
||||
|
||||
@@ -48,6 +48,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/userdata"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -493,6 +494,13 @@ func (manager *SGuestManager) ListItemFilter(
|
||||
if len(query.InstanceType) > 0 {
|
||||
q = q.In("instance_type", query.InstanceType)
|
||||
}
|
||||
if query.WithHost != nil {
|
||||
if *query.WithHost {
|
||||
q = q.IsNotEmpty("host_id")
|
||||
} else {
|
||||
q = q.IsNullOrEmpty("host_id")
|
||||
}
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
@@ -1592,6 +1600,18 @@ func (self *SGuest) PostUpdate(ctx context.Context, userCred mcclient.TokenCrede
|
||||
}
|
||||
|
||||
self.StartSyncTask(ctx, userCred, true, "")
|
||||
|
||||
if data.Contains("name") || data.Contains("__meta__") {
|
||||
err := self.StartRemoteUpdateTask(ctx, userCred, false, "")
|
||||
if err != nil {
|
||||
log.Errorf("StartRemoteUpdateTask fail: %s", err)
|
||||
}
|
||||
}
|
||||
// notify webhook
|
||||
err := notifyclient.NotifyWebhook(ctx, userCred, self, notifyclient.ActionUpdate)
|
||||
if err != nil {
|
||||
log.Errorf("unable to NotifyWebhook: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SGuestManager) checkCreateQuota(
|
||||
@@ -2465,7 +2485,10 @@ func (self *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.Token
|
||||
diff, err := db.UpdateWithLock(ctx, self, func() error {
|
||||
extVM.Refresh()
|
||||
if options.NameSyncResources.Contains(self.Keyword()) && !recycle {
|
||||
self.Name = extVM.GetName()
|
||||
newName, _ := db.GenerateAlterName(self, extVM.GetName())
|
||||
if len(newName) > 0 && newName != self.Name {
|
||||
self.Name = newName
|
||||
}
|
||||
}
|
||||
if !self.IsFailureStatus() {
|
||||
self.Status = extVM.GetStatus()
|
||||
@@ -2570,7 +2593,9 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
|
||||
|
||||
if provider.GetFactory().IsSupportPrepaidResources() {
|
||||
guest.BillingType = extVM.GetBillingType()
|
||||
guest.ExpiredAt = extVM.GetExpiredAt()
|
||||
if expired := extVM.GetExpiredAt(); !expired.IsZero() {
|
||||
guest.ExpiredAt = expired
|
||||
}
|
||||
if guest.GetDriver().IsSupportSetAutoRenew() {
|
||||
guest.AutoRenew = extVM.IsAutoRenew()
|
||||
}
|
||||
@@ -3105,12 +3130,11 @@ func (self *SGuest) SyncVMDisks(ctx context.Context, userCred mcclient.TokenCred
|
||||
|
||||
func filterGuestByRange(q *sqlchemy.SQuery, rangeObjs []db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string, brands []string, cloudEnv string) *sqlchemy.SQuery {
|
||||
hosts := HostManager.Query().SubQuery()
|
||||
subq := hosts.Query(hosts.Field("id"))
|
||||
subq = AttachUsageQuery(subq, hosts, hostTypes, resourceTypes, providers, brands, cloudEnv, rangeObjs)
|
||||
|
||||
q = q.Join(hosts, sqlchemy.Equals(hosts.Field("id"), q.Field("host_id")))
|
||||
//q = q.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
|
||||
// q = q.Filter(sqlchemy.Equals(hosts.Field("host_status"), HOST_ONLINE))
|
||||
q = q.In("host_id", subq.SubQuery())
|
||||
|
||||
q = AttachUsageQuery(q, hosts, hostTypes, resourceTypes, providers, brands, cloudEnv, rangeObjs)
|
||||
return q
|
||||
}
|
||||
|
||||
@@ -3218,7 +3242,9 @@ func _guestResourceCountQuery(
|
||||
|
||||
q = q.LeftJoin(isoDevSubQuery, sqlchemy.Equals(isoDevSubQuery.Field("guest_id"), guests.Field("id")))
|
||||
|
||||
q = filterGuestByRange(q, rangeObjs, hostTypes, resourceTypes, providers, brands, cloudEnv)
|
||||
if len(rangeObjs) > 0 || len(hostTypes) > 0 || len(resourceTypes) > 0 || len(providers) > 0 || len(brands) > 0 || len(cloudEnv) > 0 {
|
||||
q = filterGuestByRange(q, rangeObjs, hostTypes, resourceTypes, providers, brands, cloudEnv)
|
||||
}
|
||||
|
||||
switch scope {
|
||||
case rbacutils.ScopeSystem:
|
||||
@@ -3426,11 +3452,11 @@ func (self *SGuest) createDiskOnStorage(ctx context.Context, userCred mcclient.T
|
||||
return disk, nil
|
||||
}
|
||||
|
||||
func (self *SGuest) ChooseHostStorage(host *SHost, backend string, candidate *schedapi.CandidateDisk) *SStorage {
|
||||
func (self *SGuest) ChooseHostStorage(host *SHost, diskConfig *api.DiskConfig, candidate *schedapi.CandidateDisk) (*SStorage, error) {
|
||||
if candidate == nil || len(candidate.StorageIds) == 0 {
|
||||
return self.GetDriver().ChooseHostStorage(host, backend, nil)
|
||||
return self.GetDriver().ChooseHostStorage(host, diskConfig, nil)
|
||||
}
|
||||
return self.GetDriver().ChooseHostStorage(host, backend, candidate.StorageIds)
|
||||
return self.GetDriver().ChooseHostStorage(host, diskConfig, candidate.StorageIds)
|
||||
}
|
||||
|
||||
func (self *SGuest) createDiskOnHost(
|
||||
@@ -3445,7 +3471,10 @@ func (self *SGuest) createDiskOnHost(
|
||||
backupCandidate *schedapi.CandidateDisk,
|
||||
autoAttach bool,
|
||||
) (*SDisk, error) {
|
||||
var storage *SStorage
|
||||
var (
|
||||
storage *SStorage
|
||||
err error
|
||||
)
|
||||
if len(diskConfig.Storage) > 0 {
|
||||
_storage, err := StorageManager.FetchByIdOrName(userCred, diskConfig.Storage)
|
||||
if err != nil {
|
||||
@@ -3456,7 +3485,10 @@ func (self *SGuest) createDiskOnHost(
|
||||
}
|
||||
storage = _storage.(*SStorage)
|
||||
} else {
|
||||
storage = self.ChooseHostStorage(host, diskConfig.Backend, candidate)
|
||||
storage, err = self.ChooseHostStorage(host, diskConfig, candidate)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ChooseHostStorage")
|
||||
}
|
||||
}
|
||||
if storage == nil {
|
||||
return nil, fmt.Errorf("No storage on %s to create disk for %s", host.GetName(), diskConfig.Backend)
|
||||
@@ -3468,7 +3500,10 @@ func (self *SGuest) createDiskOnHost(
|
||||
}
|
||||
if len(self.BackupHostId) > 0 {
|
||||
backupHost := HostManager.FetchHostById(self.BackupHostId)
|
||||
backupStorage := self.ChooseHostStorage(backupHost, diskConfig.Backend, backupCandidate)
|
||||
backupStorage, err := self.ChooseHostStorage(backupHost, diskConfig, backupCandidate)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ChooseHostStorage")
|
||||
}
|
||||
diff, err := db.Update(disk, func() error {
|
||||
disk.BackupStorageId = backupStorage.Id
|
||||
return nil
|
||||
@@ -5466,3 +5501,24 @@ func (manager *SGuestManager) ValidateNameLoginAccount(name string) error {
|
||||
}
|
||||
return httperrors.NewInputParameterError("name starts with letter, and contains letter, number and - only")
|
||||
}
|
||||
|
||||
func (guest *SGuest) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
|
||||
data := jsonutils.NewDict()
|
||||
if replaceTags {
|
||||
data.Add(jsonutils.JSONTrue, "replace_tags")
|
||||
}
|
||||
if task, err := taskman.TaskManager.NewTask(ctx, "GuestRemoteUpdateTask", guest, userCred, data, parentTaskId, "", nil); err != nil {
|
||||
log.Errorln(err)
|
||||
return errors.Wrap(err, "Start GuestRemoteUpdateTask")
|
||||
} else {
|
||||
task.ScheduleRun(nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (guest *SGuest) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
|
||||
err := guest.StartRemoteUpdateTask(ctx, userCred, false, "")
|
||||
if err != nil {
|
||||
log.Errorf("StartRemoteUpdateTask fail: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,10 @@ func ValidateScheduleCreateData(ctx context.Context, userCred mcclient.TokenCred
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defaultStorage := GetDriver(hypervisor).ChooseHostStorage(baremetal, "", nil)
|
||||
defaultStorage, err := GetDriver(hypervisor).ChooseHostStorage(baremetal, &api.DiskConfig{}, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ChooseHostStorage")
|
||||
}
|
||||
if defaultStorage == nil {
|
||||
return nil, httperrors.NewInsufficientResourceError("no valid storage on host")
|
||||
}
|
||||
|
||||
@@ -151,7 +151,6 @@ func (manager *SLoadbalancerCertificateManager) FetchCustomizeColumns(
|
||||
func (lbcert *SLoadbalancerCertificate) ValidateDeleteCondition(ctx context.Context) error {
|
||||
men := []db.IModelManager{
|
||||
LoadbalancerListenerManager,
|
||||
CachedLoadbalancerCertificateManager,
|
||||
}
|
||||
lbcertId := lbcert.Id
|
||||
for _, man := range men {
|
||||
@@ -169,6 +168,20 @@ func (lbcert *SLoadbalancerCertificate) ValidateDeleteCondition(ctx context.Cont
|
||||
lbcertId, n, man.KeywordPlural())
|
||||
}
|
||||
}
|
||||
|
||||
// cache delete condition
|
||||
caches, err := lbcert.GetCachedCerts()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetCachedCerts")
|
||||
}
|
||||
|
||||
for i := range caches {
|
||||
err := caches[i].ValidateDeleteCondition(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ValidateDeleteCondition")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -182,6 +195,18 @@ func (lbcert *SLoadbalancerCertificate) PerformPurge(ctx context.Context, userCr
|
||||
|
||||
func (lbcert *SLoadbalancerCertificate) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
if !lbcert.PendingDeleted {
|
||||
caches, err := lbcert.GetCachedCerts()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetCachedCerts")
|
||||
}
|
||||
|
||||
for i := range caches {
|
||||
err := caches[i].MarkPendingDelete(userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "MarkPendingDelete")
|
||||
}
|
||||
}
|
||||
|
||||
return lbcert.DoPendingDelete(ctx, userCred)
|
||||
}
|
||||
|
||||
|
||||
@@ -301,7 +301,9 @@ func newLocalBackendFromCloudLoadbalancerBackend(ctx context.Context, userCred m
|
||||
sq := HostManager.Query().SubQuery()
|
||||
return q.Join(sq, sqlchemy.Equals(sq.Field("id"), q.Field("host_id"))).Filter(sqlchemy.Equals(sq.Field("manager_id"), lbbgProvider.Id))
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
guest := instance.(*SGuest)
|
||||
//address, err := LoadbalancerBackendManager.GetGuestAddress(guest)
|
||||
//if err != nil {
|
||||
|
||||
@@ -246,7 +246,10 @@ func (man *SOpenstackCachedLbManager) newFromCloudLoadbalancerBackend(ctx contex
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// openstack lb后端是ip:port 不一定有server映射
|
||||
if len(extLoadbalancerBackend.GetBackendId()) == 0 {
|
||||
return nil, errors.Wrap(cloudprovider.ErrNotFound, "extLoadbalancerBackend.GetBackendId()")
|
||||
}
|
||||
locallbb, err := newLocalBackendFromCloudLoadbalancerBackend(ctx, userCred, localBackendGroup, extLoadbalancerBackend, syncOwnerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -518,7 +518,7 @@ func _managedResourceFilterByAccount(managerIdFieldName string, q *sqlchemy.SQue
|
||||
if len(cloudaccountArr) > 0 {
|
||||
cpq := CloudaccountManager.Query().SubQuery()
|
||||
subcpq := cpq.Query(cpq.Field("id")).Filter(sqlchemy.OR(
|
||||
sqlchemy.In(cpq.Field("id"), cloudaccountArr),
|
||||
sqlchemy.In(cpq.Field("id"), stringutils2.RemoveUtf8Strings(cloudaccountArr)),
|
||||
sqlchemy.In(cpq.Field("name"), cloudaccountArr),
|
||||
)).SubQuery()
|
||||
subq := CloudproviderManager.Query("id").In("cloudaccount_id", subcpq).SubQuery()
|
||||
|
||||
@@ -363,7 +363,9 @@ func (self *SNatGateway) SyncWithCloudNatGateway(ctx context.Context, userCred m
|
||||
factory, _ := provider.GetProviderFactory()
|
||||
if factory.IsSupportPrepaidResources() {
|
||||
self.BillingType = extNat.GetBillingType()
|
||||
self.ExpiredAt = extNat.GetExpiredAt()
|
||||
if expired := extNat.GetExpiredAt(); !expired.IsZero() {
|
||||
self.ExpiredAt = expired
|
||||
}
|
||||
self.AutoRenew = extNat.IsAutoRenew()
|
||||
}
|
||||
|
||||
@@ -407,7 +409,9 @@ func (manager *SNatGatewayManager) newFromCloudNatGateway(ctx context.Context, u
|
||||
factory, _ := provider.GetProviderFactory()
|
||||
if factory.IsSupportPrepaidResources() {
|
||||
nat.BillingType = extNat.GetBillingType()
|
||||
nat.ExpiredAt = extNat.GetExpiredAt()
|
||||
if expired := extNat.GetExpiredAt(); !expired.IsZero() {
|
||||
nat.ExpiredAt = expired
|
||||
}
|
||||
nat.AutoRenew = extNat.IsAutoRenew()
|
||||
}
|
||||
|
||||
|
||||
@@ -1333,6 +1333,20 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred
|
||||
return input, httperrors.NewInputParameterError("Invalid server_type: %s", input.ServerType)
|
||||
}
|
||||
|
||||
{
|
||||
defaultVlanId := 1
|
||||
|
||||
if input.VlanId == nil {
|
||||
input.VlanId = &defaultVlanId
|
||||
} else if *input.VlanId < 1 {
|
||||
input.VlanId = &defaultVlanId
|
||||
}
|
||||
|
||||
if *input.VlanId > 4095 {
|
||||
return input, httperrors.NewInputParameterError("valid vlan id")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if len(input.IfnameHint) == 0 {
|
||||
input.IfnameHint = input.Name
|
||||
|
||||
@@ -196,7 +196,8 @@ func (self *SRegionQuota) FetchUsage(ctx context.Context) error {
|
||||
self.ObjectGB = int(bucketUsage.Bytes / 1000 / 1000 / 1000)
|
||||
self.ObjectCnt = bucketUsage.Objects
|
||||
|
||||
self.Rds, _ = DBInstanceManager.TotalCount(scope, ownerId, rangeObjs, providers, brands, regionKeys.CloudEnv)
|
||||
rdsUsage, _ := DBInstanceManager.TotalCount(scope, ownerId, rangeObjs, providers, brands, regionKeys.CloudEnv)
|
||||
self.Rds = rdsUsage.TotalRdsCount
|
||||
self.Cache, _ = ElasticcacheManager.TotalCount(scope, ownerId, rangeObjs, providers, brands, regionKeys.CloudEnv)
|
||||
|
||||
self.Loadbalancer, _ = LoadbalancerManager.TotalCount(scope, ownerId, rangeObjs, providers, brands, regionKeys.CloudEnv)
|
||||
|
||||
@@ -943,6 +943,7 @@ func (manager *SSecurityGroupManager) newFromCloudSecgroup(ctx context.Context,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secgroup.Status = api.SECGROUP_STATUS_READY
|
||||
secgroup.Description = extSec.GetDescription()
|
||||
secgroup.ProjectId = provider.ProjectId
|
||||
secgroup.DomainId = provider.DomainId
|
||||
|
||||
@@ -17,6 +17,8 @@ package models
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
@@ -215,7 +217,10 @@ func (manager *SSnapshotPolicyManager) OnCreateComplete(ctx context.Context, ite
|
||||
userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
for i := range items {
|
||||
sp := items[i].(*SSnapshotPolicy)
|
||||
sp.SetStatus(userCred, api.SNAPSHOT_POLICY_READY, "create complete")
|
||||
db.Update(sp, func() error {
|
||||
sp.Status = api.SNAPSHOT_POLICY_READY
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,11 +315,11 @@ func (sp *SSnapshotPolicy) DetachAfterDelete(ctx context.Context, userCred mccli
|
||||
|
||||
func (sp *SSnapshotPolicy) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
||||
// check if sp bind to some disks
|
||||
sds, err := SnapshotPolicyDiskManager.FetchAllBySnapshotpolicyID(ctx, userCred, sp.GetId())
|
||||
count, err := SnapshotPolicyDiskManager.FetchDiskCountBySPID(sp.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch bind info failed")
|
||||
return errors.Wrap(err, "unable to FetchDiskCountBySPID")
|
||||
}
|
||||
if len(sds) != 0 {
|
||||
if count != 0 {
|
||||
return httperrors.NewBadRequestError("Couldn't delete snapshot policy binding to disks")
|
||||
}
|
||||
sp.SetStatus(userCred, api.SNAPSHOT_POLICY_DELETING, "")
|
||||
@@ -365,8 +370,8 @@ func (sp *SSnapshotPolicy) GetExtraDetails(
|
||||
}
|
||||
|
||||
func (sp *SSnapshotPolicy) getMoreDetails(out api.SnapshotPolicyDetails) api.SnapshotPolicyDetails {
|
||||
out.RepeatWeekdays = SnapshotPolicyManager.RepeatWeekdaysToIntArray(sp.RepeatWeekdays)
|
||||
out.TimePoints = SnapshotPolicyManager.TimePointsToIntArray(sp.TimePoints)
|
||||
out.RepeatWeekdaysDisplay = SnapshotPolicyManager.RepeatWeekdaysToIntArray(sp.RepeatWeekdays)
|
||||
out.TimePointsDisplay = SnapshotPolicyManager.TimePointsToIntArray(sp.TimePoints)
|
||||
out.BindingDiskCount, _ = SnapshotPolicyDiskManager.FetchDiskCountBySPID(sp.Id)
|
||||
return out
|
||||
}
|
||||
@@ -722,6 +727,53 @@ func (self *SSnapshotPolicyManager) TimePointsToIntArray(n uint32) []int {
|
||||
return bitmap.Uint2IntArray(n)
|
||||
}
|
||||
|
||||
func (sp *SSnapshotPolicy) ComputeNextSyncTime(base, lastSyncTime time.Time) time.Time {
|
||||
if base.IsZero() {
|
||||
base = time.Now()
|
||||
}
|
||||
base = base.Truncate(time.Hour)
|
||||
|
||||
baseWeekday := int(base.Weekday())
|
||||
if baseWeekday == 0 {
|
||||
baseWeekday = 7
|
||||
}
|
||||
weekDays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(sp.RepeatWeekdays)
|
||||
weekDays = append(weekDays, weekDays[0]+7)
|
||||
index := sort.SearchInts(weekDays, baseWeekday)
|
||||
addDay := weekDays[index] - baseWeekday
|
||||
nextTime := base.AddDate(0, 0, addDay)
|
||||
|
||||
// find timePoint closest to the base
|
||||
timePoints := SnapshotPolicyManager.TimePointsToIntArray(sp.TimePoints)
|
||||
var newHour int
|
||||
if addDay > 0 {
|
||||
newHour = timePoints[0]
|
||||
} else {
|
||||
baseHour := base.Hour()
|
||||
index := sort.SearchInts(timePoints, baseHour)
|
||||
index = index % len(timePoints)
|
||||
if timePoints[index] == baseHour {
|
||||
index = index + 1
|
||||
newHour = timePoints[index]
|
||||
} else {
|
||||
newHour = timePoints[index]
|
||||
}
|
||||
}
|
||||
nextTime = time.Date(nextTime.Year(), nextTime.Month(), nextTime.Day(), newHour, 0, 0, 0, base.Location())
|
||||
|
||||
if sp.RetentionDays <= 0 {
|
||||
return nextTime
|
||||
}
|
||||
if lastSyncTime.IsZero() {
|
||||
lastSyncTime = base
|
||||
}
|
||||
snapshotRentionExpired := lastSyncTime.AddDate(0, 0, sp.RetentionDays)
|
||||
if snapshotRentionExpired.Before(nextTime) {
|
||||
return snapshotRentionExpired
|
||||
}
|
||||
return nextTime
|
||||
}
|
||||
|
||||
func (sp *SSnapshotPolicy) GenerateCreateSpParams() *cloudprovider.SnapshotPolicyInput {
|
||||
intWeekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(sp.RepeatWeekdays)
|
||||
intTimePoints := SnapshotPolicyManager.TimePointsToIntArray(sp.TimePoints)
|
||||
|
||||
@@ -20,10 +20,12 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
@@ -73,9 +75,8 @@ type SSnapshotPolicyDisk struct {
|
||||
|
||||
SSnapshotPolicyResourceBase `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
|
||||
SDiskResourceBase `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
|
||||
// SnapshotpolicyId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
|
||||
// DiskId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
|
||||
Status string `width:"36" charset:"ascii" nullable:"false" default:"init" list:"user" create:"optional"`
|
||||
Status string `width:"36" charset:"ascii" nullable:"false" default:"init" list:"user" create:"optional"`
|
||||
NextSyncTime time.Time
|
||||
}
|
||||
|
||||
func (sd *SSnapshotPolicyDisk) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error {
|
||||
@@ -171,6 +172,41 @@ func (m *SSnapshotPolicyDiskManager) FetchBySnapshotPolicyDisk(spId, diskId stri
|
||||
return &ret[0], nil
|
||||
}
|
||||
|
||||
func (sdm *SSnapshotPolicyDiskManager) InitalizeData() error {
|
||||
q := sdm.Query().IsNullOrEmpty("next_sync_time")
|
||||
var sds []SSnapshotPolicyDisk
|
||||
err := db.FetchModelObjects(sdm, q, &sds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// fetch all snapshotpolicy
|
||||
spIdSet := sets.NewString()
|
||||
for i := range sds {
|
||||
spIdSet.Insert(sds[i].SnapshotpolicyId)
|
||||
}
|
||||
sps, err := SnapshotPolicyManager.FetchAllByIds(spIdSet.UnsortedList())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "FetchAllByIds")
|
||||
}
|
||||
spMap := make(map[string]*SSnapshotPolicy, len(sps))
|
||||
for i := range sps {
|
||||
spMap[sps[i].GetId()] = &sps[i]
|
||||
}
|
||||
now := time.Now()
|
||||
for i := range sds {
|
||||
sd := &sds[i]
|
||||
_, err := db.Update(sd, func() error {
|
||||
sd.NextSyncTime = spMap[sd.SnapshotpolicyId].ComputeNextSyncTime(now, now)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "db.Update")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SSnapshotPolicyDiskManager) FetchAllByDiskID(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
diskID string) ([]SSnapshotPolicyDisk, error) {
|
||||
|
||||
@@ -420,6 +456,8 @@ func (self *SSnapshotPolicyDiskManager) newSnapshotpolicyDisk(ctx context.Contex
|
||||
spd := SSnapshotPolicyDisk{}
|
||||
spd.SnapshotpolicyId = sp.GetId()
|
||||
spd.DiskId = disk.GetId()
|
||||
now := time.Now()
|
||||
spd.NextSyncTime = sp.ComputeNextSyncTime(now, now)
|
||||
spd.SetModelManager(self, &spd)
|
||||
|
||||
lockman.LockJointObject(ctx, disk, sp)
|
||||
@@ -456,6 +494,16 @@ func (self *SSnapshotPolicyDiskManager) ValidateCreateData(ctx context.Context,
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (sd *SSnapshotPolicyDisk) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
||||
sp, err := SnapshotPolicyManager.FetchSnapshotPolicyById(sd.SnapshotpolicyId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
now := time.Now()
|
||||
sd.NextSyncTime = sp.ComputeNextSyncTime(now, now)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sd *SSnapshotPolicyDisk) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.
|
||||
IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
|
||||
|
||||
@@ -621,6 +621,11 @@ func (self *SSnapshot) ValidateDeleteCondition(ctx context.Context) error {
|
||||
if count > 0 {
|
||||
return httperrors.NewBadRequestError("snapshot referenced by instance snapshot")
|
||||
}
|
||||
if disk, err := self.GetDisk(); err == nil {
|
||||
if disk.Status == api.DISK_RESET {
|
||||
return httperrors.NewBadRequestError("Cannot delete snapshot on disk reset")
|
||||
}
|
||||
}
|
||||
driver := self.GetRegionDriver()
|
||||
if driver != nil {
|
||||
return driver.ValidateSnapshotDelete(ctx, self)
|
||||
|
||||
@@ -133,7 +133,7 @@ func (self *SStoragecache) GetRegion() (*SCloudregion, error) {
|
||||
return region, nil
|
||||
}
|
||||
|
||||
func (self *SStoragecache) getHostId() (string, error) {
|
||||
func (self *SStoragecache) GetHosts() ([]SHost, error) {
|
||||
hoststorages := HoststorageManager.Query().SubQuery()
|
||||
storages := StorageManager.Query().SubQuery()
|
||||
|
||||
@@ -153,7 +153,15 @@ func (self *SStoragecache) getHostId() (string, error) {
|
||||
sqlchemy.IsTrue(storages.Field("enabled")))).
|
||||
Filter(sqlchemy.Equals(hoststorages.Field("storage_id"), storages.Field("id"))).All(&hosts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func (self *SStoragecache) getHostId() (string, error) {
|
||||
hosts, err := self.GetHosts()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetHosts")
|
||||
}
|
||||
|
||||
hostIds := make([]string, 0)
|
||||
|
||||
@@ -1399,6 +1399,17 @@ func (manager *SStorageManager) ListItemFilter(
|
||||
q = q.In("id", subq.SubQuery())
|
||||
}
|
||||
|
||||
if len(query.ImageId) > 0 {
|
||||
image, err := CachedimageManager.getImageInfo(ctx, userCred, query.ImageId, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "CachedimageManager.getImageInfo")
|
||||
}
|
||||
subq := StorageManager.Query("id")
|
||||
storagecaches := StoragecachedimageManager.Query("storagecache_id").Equals("cachedimage_id", image.Id).SubQuery()
|
||||
subq = subq.Join(storagecaches, sqlchemy.Equals(subq.Field("storagecache_id"), storagecaches.Field("storagecache_id")))
|
||||
q = q.In("id", subq.SubQuery())
|
||||
}
|
||||
|
||||
return q, err
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
syncAccountWorker *appsrv.SWorkerManager
|
||||
syncWorkers []*appsrv.SWorkerManager
|
||||
syncWorkerRing *hashring.HashRing
|
||||
syncSecgroupWorker *appsrv.SWorkerManager
|
||||
syncAccountWorker *appsrv.SWorkerManager
|
||||
syncWorkers []*appsrv.SWorkerManager
|
||||
syncWorkerRing *hashring.HashRing
|
||||
)
|
||||
|
||||
func InitSyncWorkers(count int) {
|
||||
@@ -50,6 +51,12 @@ func InitSyncWorkers(count int) {
|
||||
2048,
|
||||
true,
|
||||
)
|
||||
syncSecgroupWorker = appsrv.NewWorkerManager(
|
||||
"syncSecgroupProbeWorkerManager",
|
||||
1,
|
||||
2048,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func RunSyncCloudproviderRegionTask(key string, syncFunc func()) {
|
||||
@@ -62,3 +69,7 @@ func RunSyncCloudproviderRegionTask(key string, syncFunc func()) {
|
||||
func RunSyncCloudAccountTask(probeFunc func()) {
|
||||
syncAccountWorker.Run(probeFunc, nil, nil)
|
||||
}
|
||||
|
||||
func RunSyncSecgroupTask(syncFunc func()) {
|
||||
syncSecgroupWorker.Run(syncFunc, nil, nil)
|
||||
}
|
||||
|
||||
@@ -144,7 +144,10 @@ type ComputeOptions struct {
|
||||
|
||||
EnableAutoRenameProject bool `help:"when it set true, auto create project will rename when cloud project name changed" default:"false"`
|
||||
|
||||
SyncStorageCapacityUsedIntervalMinutes int `help:"interval sync storage capacity used" default:"10"`
|
||||
SyncStorageCapacityUsedIntervalMinutes int `help:"interval sync storage capacity used" default:"10"`
|
||||
LockStorageFromCachedimage bool `help:"must use storage in where selected cachedimage when creating vm"`
|
||||
|
||||
SyncExtDiskSnapshotIntervalMinutes int `help:"sync snapshot for external disk" default:"20"`
|
||||
|
||||
SCapabilityOptions
|
||||
SASControllerOptions
|
||||
|
||||
@@ -1480,95 +1480,109 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
|
||||
return "", errors.Wrap(err, "SSecurityGroupCache.Register")
|
||||
}
|
||||
|
||||
iRegion, err := vpc.GetIRegion()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "vpc.GetIRegion")
|
||||
}
|
||||
waitChan := make(chan error)
|
||||
|
||||
var iSecgroup cloudprovider.ICloudSecurityGroup = nil
|
||||
if len(cache.ExternalId) > 0 {
|
||||
iSecgroup, err = iRegion.GetISecurityGroupById(cache.ExternalId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
return "", errors.Wrap(err, "iRegion.GetSecurityGroupById")
|
||||
}
|
||||
cache.ExternalId = ""
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.ExternalId) == 0 {
|
||||
if strings.ToLower(secgroup.Name) == "default" { //避免有些云不支持default关键字
|
||||
secgroup.Name = "DefaultGroup"
|
||||
}
|
||||
// 避免有的云不支持重名安全组
|
||||
randomString := func(prefix string, length int) string {
|
||||
return fmt.Sprintf("%s-%s", prefix, rand.String(length))
|
||||
}
|
||||
opts := &cloudprovider.SecurityGroupFilterOptions{
|
||||
Name: randomString(secgroup.Name, 1),
|
||||
VpcId: vpcId,
|
||||
ProjectId: remoteProjectId,
|
||||
}
|
||||
for i := 2; i < 30; i++ {
|
||||
_, err := iRegion.GetISecurityGroupByName(opts)
|
||||
models.RunSyncSecgroupTask(func() {
|
||||
err := func() error {
|
||||
iRegion, err := vpc.GetIRegion()
|
||||
if err != nil {
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
break
|
||||
}
|
||||
if errors.Cause(err) != cloudprovider.ErrDuplicateId {
|
||||
return "", err
|
||||
return errors.Wrap(err, "vpc.GetIRegion")
|
||||
}
|
||||
|
||||
var iSecgroup cloudprovider.ICloudSecurityGroup = nil
|
||||
if len(cache.ExternalId) > 0 {
|
||||
iSecgroup, err = iRegion.GetISecurityGroupById(cache.ExternalId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
return errors.Wrap(err, "iRegion.GetSecurityGroupById")
|
||||
}
|
||||
cache.ExternalId = ""
|
||||
}
|
||||
}
|
||||
opts.Name = randomString(secgroup.Name, i)
|
||||
}
|
||||
conf := &cloudprovider.SecurityGroupCreateInput{
|
||||
Name: opts.Name,
|
||||
Desc: secgroup.Description,
|
||||
VpcId: vpcId,
|
||||
ProjectId: remoteProjectId,
|
||||
Rules: secgroup.GetSecRules(""),
|
||||
}
|
||||
iSecgroup, err = iRegion.CreateISecurityGroup(conf)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "iRegion.CreateISecurityGroup")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = db.Update(cache, func() error {
|
||||
cache.ExternalId = iSecgroup.GetGlobalId()
|
||||
cache.Name = iSecgroup.GetName()
|
||||
cache.Status = api.SECGROUP_CACHE_STATUS_READY
|
||||
return nil
|
||||
if len(cache.ExternalId) == 0 {
|
||||
if strings.ToLower(secgroup.Name) == "default" { //避免有些云不支持default关键字
|
||||
secgroup.Name = "DefaultGroup"
|
||||
}
|
||||
// 避免有的云不支持重名安全组
|
||||
randomString := func(prefix string, length int) string {
|
||||
return fmt.Sprintf("%s-%s", prefix, rand.String(length))
|
||||
}
|
||||
opts := &cloudprovider.SecurityGroupFilterOptions{
|
||||
Name: randomString(secgroup.Name, 1),
|
||||
VpcId: vpcId,
|
||||
ProjectId: remoteProjectId,
|
||||
}
|
||||
for i := 2; i < 30; i++ {
|
||||
_, err := iRegion.GetISecurityGroupByName(opts)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
break
|
||||
}
|
||||
if errors.Cause(err) != cloudprovider.ErrDuplicateId {
|
||||
return errors.Wrapf(err, "GetISecurityGroupByName")
|
||||
}
|
||||
}
|
||||
opts.Name = randomString(secgroup.Name, i)
|
||||
}
|
||||
conf := &cloudprovider.SecurityGroupCreateInput{
|
||||
Name: opts.Name,
|
||||
Desc: secgroup.Description,
|
||||
VpcId: vpcId,
|
||||
ProjectId: remoteProjectId,
|
||||
Rules: secgroup.GetSecRules(""),
|
||||
}
|
||||
iSecgroup, err = iRegion.CreateISecurityGroup(conf)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "iRegion.CreateISecurityGroup")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = db.Update(cache, func() error {
|
||||
cache.ExternalId = iSecgroup.GetGlobalId()
|
||||
cache.Name = iSecgroup.GetName()
|
||||
cache.Status = api.SECGROUP_CACHE_STATUS_READY
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "db.Update")
|
||||
}
|
||||
|
||||
rules, err := iSecgroup.GetRules()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "iSecgroup.GetRules")
|
||||
}
|
||||
|
||||
maxPriority := region.GetDriver().GetSecurityGroupRuleMaxPriority()
|
||||
minPriority := region.GetDriver().GetSecurityGroupRuleMinPriority()
|
||||
|
||||
defaultInRule := region.GetDriver().GetDefaultSecurityGroupInRule()
|
||||
defaultOutRule := region.GetDriver().GetDefaultSecurityGroupOutRule()
|
||||
order := region.GetDriver().GetSecurityGroupRuleOrder()
|
||||
onlyAllowRules := region.GetDriver().IsOnlySupportAllowRules()
|
||||
|
||||
localRules := secrules.SecurityRuleSet(secgroup.GetSecRules(""))
|
||||
|
||||
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, localRules, rules, defaultInRule, defaultOutRule, onlyAllowRules, false)
|
||||
|
||||
if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 {
|
||||
return nil
|
||||
}
|
||||
return iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels)
|
||||
}()
|
||||
|
||||
waitChan <- err
|
||||
})
|
||||
|
||||
err = <-waitChan
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "db.Update")
|
||||
return "", err
|
||||
}
|
||||
|
||||
rules, err := iSecgroup.GetRules()
|
||||
cache, err = models.SecurityGroupCacheManager.Register(ctx, userCred, secgroup.Id, vpcId, region.Id, vpc.ManagerId, remoteProjectId)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "iSecgroup.GetRules")
|
||||
}
|
||||
|
||||
maxPriority := region.GetDriver().GetSecurityGroupRuleMaxPriority()
|
||||
minPriority := region.GetDriver().GetSecurityGroupRuleMinPriority()
|
||||
|
||||
defaultInRule := region.GetDriver().GetDefaultSecurityGroupInRule()
|
||||
defaultOutRule := region.GetDriver().GetDefaultSecurityGroupOutRule()
|
||||
order := region.GetDriver().GetSecurityGroupRuleOrder()
|
||||
onlyAllowRules := region.GetDriver().IsOnlySupportAllowRules()
|
||||
|
||||
localRules := secrules.SecurityRuleSet(secgroup.GetSecRules(""))
|
||||
|
||||
common, inAdds, outAdds, inDels, outDels := cloudprovider.CompareRules(minPriority, maxPriority, order, localRules, rules, defaultInRule, defaultOutRule, onlyAllowRules, false)
|
||||
|
||||
if len(inAdds) == 0 && len(inDels) == 0 && len(outAdds) == 0 && len(outDels) == 0 {
|
||||
return cache.ExternalId, nil
|
||||
}
|
||||
|
||||
err = iSecgroup.SyncRules(common, inAdds, outAdds, inDels, outDels)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "iSecgroup.SyncRules")
|
||||
return "", errors.Wrap(err, "SSecurityGroupCache.Register")
|
||||
}
|
||||
|
||||
return cache.ExternalId, nil
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user