diff --git a/cmd/climc/shell/compute/wires.go b/cmd/climc/shell/compute/wires.go index e8686ea161..11b94a4e01 100644 --- a/cmd/climc/shell/compute/wires.go +++ b/cmd/climc/shell/compute/wires.go @@ -33,4 +33,5 @@ func init() { cmd.PerformWithKeyword("merge", "merge-from", new(options.WireMergeOptions)) cmd.Perform("merge-network", new(options.WireOptions)) cmd.Get("topology", &options.WireOptions{}) + cmd.Perform("set-class-metadata", &options.ResourceMetadataOptions{}) } diff --git a/pkg/cloudcommon/db/standalone_anon.go b/pkg/cloudcommon/db/standalone_anon.go index 768e879545..2ad531d281 100644 --- a/pkg/cloudcommon/db/standalone_anon.go +++ b/pkg/cloudcommon/db/standalone_anon.go @@ -299,24 +299,45 @@ func (model *SStandaloneAnonResourceBase) SetClassMetadataAll(ctx context.Contex return nil } -func (model *SStandaloneAnonResourceBase) Inherit(ctx context.Context, sonModel *SStandaloneAnonResourceBase) error { - return Inherit(ctx, model, sonModel) +func (model *SStandaloneAnonResourceBase) InheritTo(ctx context.Context, dest IClassMetadataSetter) error { + return InheritFromTo(ctx, model, dest) } type IClassMetadataSetter interface { + // a setter should first be a owner + IClassMetadataOwner + SetClassMetadataAll(context.Context, map[string]string, mcclient.TokenCredential) error } -func Inherit(ctx context.Context, parent IClassMetadataOwner, son IClassMetadataSetter) error { - metadata, err := parent.GetAllClassMetadata() +func InheritFromTo(ctx context.Context, src IClassMetadataOwner, dest IClassMetadataSetter) error { + metadata, err := src.GetAllClassMetadata() if err != nil { return errors.Wrap(err, "GetAllClassMetadata") } if len(metadata) == 0 { return nil } + curMeta, err := dest.GetAllClassMetadata() + if err != nil { + return errors.Wrap(err, "GetAllClassMetadata dest") + } + if len(curMeta) > 0 { + // check conflict + for k, v := range curMeta { + if sv, ok := metadata[k]; ok { + if sv != v { + // duplicate value for identical key + return errors.Wrapf(httperrors.ErrConflict, "destination has another value for class key %s", k) + } + } else { + // no such class key + return errors.Wrapf(httperrors.ErrConflict, "destination has extra class key %s", k) + } + } + } userCred := auth.AdminCredential() - return son.SetClassMetadataAll(ctx, metadata, userCred) + return dest.SetClassMetadataAll(ctx, metadata, userCred) } type IClassMetadataOwner interface { diff --git a/pkg/cloudcommon/db/virtualresource.go b/pkg/cloudcommon/db/virtualresource.go index 23b2883e4b..867fd33336 100644 --- a/pkg/cloudcommon/db/virtualresource.go +++ b/pkg/cloudcommon/db/virtualresource.go @@ -288,7 +288,7 @@ func (model *SVirtualResourceBase) PostCreate(ctx context.Context, userCred mccl log.Errorf("unable to GetTenantCache: %s", err.Error()) return } - err = Inherit(ctx, project, model) + err = InheritFromTo(ctx, project, model) if err != nil { log.Errorf("unable to inherit class metadata from poject %s: %s", project.GetId(), err.Error()) } diff --git a/pkg/compute/models/backup.go b/pkg/compute/models/backup.go index 08460083cf..c11b41adde 100644 --- a/pkg/compute/models/backup.go +++ b/pkg/compute/models/backup.go @@ -280,7 +280,7 @@ func (db *SDiskBackup) PostCreate(ctx context.Context, userCred mcclient.TokenCr if err != nil { log.Errorf("unable to GetDisk: %s", err.Error()) } - err = disk.Inherit(ctx, &db.SStandaloneAnonResourceBase) + err = disk.InheritTo(ctx, db) if err != nil { log.Errorf("unable to inherit from disk %s to backup %s: %s", disk.GetId(), db.GetId(), err.Error()) } diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index f05dac7302..68b93e31f9 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -4733,7 +4733,7 @@ func (self *SGuest) PerformInstanceSnapshot( ctx, userCred, pendingUsage, pendingUsage, false) return nil, httperrors.NewInternalServerError("create instance snapshot failed: %s", err) } - err = self.Inherit(ctx, &instanceSnapshot.SStandaloneAnonResourceBase) + err = self.InheritTo(ctx, instanceSnapshot) if err != nil { return nil, errors.Wrapf(err, "unable to inherit from guest %s to instance snapshot %s", self.GetId(), instanceSnapshot.GetId()) } @@ -4776,7 +4776,7 @@ func (self *SGuest) PerformInstanceBackup(ctx context.Context, userCred mcclient if err != nil { return nil, httperrors.NewInternalServerError("create instance backup failed: %s", err) } - err = self.Inherit(ctx, &instanceBackup.SStandaloneAnonResourceBase) + err = self.InheritTo(ctx, instanceBackup) if err != nil { return nil, errors.Wrapf(err, "unable to inherit from guest %s to instance backup %s", self.GetId(), instanceBackup.GetId()) } diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index fda011a163..725945224f 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3856,7 +3856,7 @@ func (self *SGuest) createDiskOnHost( if autoAttach { err = self.attach2Disk(ctx, disk, userCred, diskConfig.Driver, diskConfig.Cache, diskConfig.Mountpoint) } - err = self.Inherit(ctx, &disk.SStandaloneAnonResourceBase) + err = self.InheritTo(ctx, disk) if err != nil { return nil, errors.Wrapf(err, "unable to inherit from guest %s to disk %s", self.GetId(), disk.GetId()) } diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 149bcaac89..26dc55deb1 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -4276,7 +4276,7 @@ func (self *SHost) addNetif(ctx context.Context, userCred mcclient.TokenCredenti } // inherit wire's class metadata if sw != nil { - err := db.Inherit(ctx, sw, self) + err := db.InheritFromTo(ctx, sw, self) if err != nil { return errors.Wrapf(err, "unable to inherit class metadata from sw %s", sw.GetName()) } diff --git a/pkg/compute/models/hostwires.go b/pkg/compute/models/hostwires.go index 527714c3b0..12bd0d94e4 100644 --- a/pkg/compute/models/hostwires.go +++ b/pkg/compute/models/hostwires.go @@ -290,3 +290,19 @@ func (manager *SHostwireManager) ListItemExportKeys(ctx context.Context, return q, nil } + +func (hw *SHostwire) PostCreate( + ctx context.Context, + userCred mcclient.TokenCredential, + ownerId mcclient.IIdentityProvider, + query jsonutils.JSONObject, + data jsonutils.JSONObject, +) { + hw.SHostJointsBase.PostCreate(ctx, userCred, ownerId, query, data) + host := hw.GetHost() + wire := hw.GetWire() + err := db.InheritFromTo(ctx, wire, host) + if err != nil { + log.Errorf("Inherit class metadata from host to wire fail: %s", err) + } +} diff --git a/pkg/compute/models/instance_snapshots.go b/pkg/compute/models/instance_snapshots.go index c7d0144d37..12a228c863 100644 --- a/pkg/compute/models/instance_snapshots.go +++ b/pkg/compute/models/instance_snapshots.go @@ -393,7 +393,7 @@ func (manager *SInstanceSnapshotManager) CreateInstanceSnapshot(ctx context.Cont if err != nil { return nil, errors.Wrap(err, "Insert") } - err = db.Inherit(ctx, guest, instanceSnapshot) + err = db.InheritFromTo(ctx, guest, instanceSnapshot) if err != nil { return nil, errors.Wrap(err, "Inherit ClassMetadata") } diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index 8fefa0eb10..7ca77ce968 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -2792,7 +2792,7 @@ func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, use if err != nil { return nil, errors.Wrap(err, "unable to get wire") } - err = db.Inherit(ctx, wire, newNetwork) + err = db.InheritFromTo(ctx, wire, newNetwork) if err != nil { return nil, errors.Wrap(err, "unable to inherit wire") } diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index fd36869827..1eca60e2e3 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -411,7 +411,7 @@ func (snapshot *SSnapshot) PostCreate(ctx context.Context, userCred mcclient.Tok if err != nil { log.Errorf("unable to GetDisk: %s", err.Error()) } - err = disk.Inherit(ctx, &snapshot.SStandaloneAnonResourceBase) + err = disk.InheritTo(ctx, snapshot) if err != nil { log.Errorf("unable to inherit from disk %s to snapshot %s: %s", disk.GetId(), snapshot.GetId(), err.Error()) } diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index 6d068ed84a..04d2fa2787 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -1471,7 +1471,7 @@ func (model *SWire) PostCreate(ctx context.Context, userCred mcclient.TokenCrede if err != nil { log.Errorf("unable to getvpc of wire %s: %s", model.GetId(), vpc.GetId()) } - err = db.Inherit(ctx, vpc, model) + err = db.InheritFromTo(ctx, vpc, model) if err != nil { log.Errorf("unable to inhert vpc to model %s: %s", model.GetId(), err.Error()) } diff --git a/pkg/compute/regiondrivers/kvm.go b/pkg/compute/regiondrivers/kvm.go index 7527028a16..221bd5e0a6 100644 --- a/pkg/compute/regiondrivers/kvm.go +++ b/pkg/compute/regiondrivers/kvm.go @@ -1178,7 +1178,7 @@ func (self *SKVMRegionDriver) RequestCreateInstanceSnapshot(ctx context.Context, return err } - err = isp.Inherit(ctx, &snapshot.SStandaloneAnonResourceBase) + err = isp.InheritTo(ctx, snapshot) if err != nil { return errors.Wrapf(err, "unable to inherit from instance snapshot %s to snapshot %s", isp.GetId(), snapshot.GetId()) } @@ -1333,7 +1333,7 @@ func (self *SKVMRegionDriver) RequestCreateInstanceBackup(ctx context.Context, g if err != nil { return err } - err = ib.Inherit(ctx, &backup.SStandaloneAnonResourceBase) + err = ib.InheritTo(ctx, backup) if err != nil { return errors.Wrapf(err, "unable to inherit from instance backup %s to backup %s", ib.GetId(), backup.GetId()) } diff --git a/pkg/hostman/hostinfo/hostinfo.go b/pkg/hostman/hostinfo/hostinfo.go index 3ec74c2df6..bd83754676 100644 --- a/pkg/hostman/hostinfo/hostinfo.go +++ b/pkg/hostman/hostinfo/hostinfo.go @@ -27,11 +27,11 @@ import ( "strings" "time" - "github.com/pkg/errors" "github.com/vishvananda/netlink" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/version" "yunion.io/x/pkg/utils" @@ -52,6 +52,7 @@ import ( "yunion.io/x/onecloud/pkg/hostman/options" "yunion.io/x/onecloud/pkg/hostman/storageman" "yunion.io/x/onecloud/pkg/hostman/system_service" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" "yunion.io/x/onecloud/pkg/util/cgrouputils" @@ -426,10 +427,10 @@ func (h *SHostInfo) prepareEnv() error { } szlist := hp.PageSizes() if len(szlist) == 0 { - return errors.New("invalid hugepages total size") + return errors.Error("invalid hugepages total size") } if len(szlist) > 1 { - return errors.New("cannot support more than 1 type of hugepage size") + return errors.Error("cannot support more than 1 type of hugepage size") } h.sysinfo.HugepageSizeKb = szlist[0] case "transparent": @@ -591,7 +592,7 @@ func (h *SHostInfo) EnableNativeHugepages(reservedMb int) error { return nil } } else { - return errors.New("cannot support more than 1 type of hugepage sizes") + return errors.Error("cannot support more than 1 type of hugepage sizes") } mem := h.GetMemory() if reservedMb > 0 { @@ -1794,6 +1795,10 @@ func (h *SHostInfo) unregister() { _, err := modules.Hosts.PerformAction( h.GetSession(), h.HostId, "offline", jsonutils.Marshal(map[string]string{"reason": "host stop"})) if err != nil { + if errors.Cause(err) == httperrors.ErrResourceNotFound { + log.Errorf("host not found on region, may be removed, exit cleanly") + break + } if !isLog { logclient.AddSimpleActionLog(h, logclient.ACT_OFFLINE, err, hostutils.GetComputeSession(context.Background()).GetToken(), false) isLog = true diff --git a/pkg/hostman/hostinfo/hostpinger.go b/pkg/hostman/hostinfo/hostpinger.go index 8521720e61..81d5ad767d 100644 --- a/pkg/hostman/hostinfo/hostpinger.go +++ b/pkg/hostman/hostinfo/hostpinger.go @@ -19,8 +19,10 @@ import ( "time" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/hostman/hostutils" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" ) @@ -84,7 +86,12 @@ func (p *SHostPingTask) ping(div int, hostId string) error { res, err := modules.Hosts.PerformAction(hostutils.GetComputeSession(context.Background()), hostId, "ping", nil) if err != nil { - return err + if errors.Cause(err) == httperrors.ErrResourceNotFound { + log.Errorf("host seemd removed from region ...") + return nil + } else { + return errors.Wrap(err, "ping") + } } else { name, err := res.GetString("name") if err != nil { diff --git a/pkg/mcclient/options/metadata.go b/pkg/mcclient/options/metadata.go index 687d2e95be..96ef9ae2d6 100644 --- a/pkg/mcclient/options/metadata.go +++ b/pkg/mcclient/options/metadata.go @@ -141,7 +141,11 @@ func (opts *ResourceMetadataOptions) GetId() string { func (opts *ResourceMetadataOptions) Params() (jsonutils.JSONObject, error) { params := jsonutils.NewDict() for _, tag := range opts.TAGS { - info := strings.Split(tag, "=") + sep := "=" + if strings.Index(tag, sep) < 0 { + sep = ":" + } + info := strings.Split(tag, sep) if len(info) == 2 { if len(info[0]) == 0 { return nil, fmt.Errorf("invalidate tag info %s", tag)