// Copyright 2019 Yunion // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package models import ( "context" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SHostwireManager struct { SHostJointsManager SWireResourceBaseManager } var HostwireManager *SHostwireManager func init() { db.InitManager(func() { HostwireManager = &SHostwireManager{ SHostJointsManager: NewHostJointsManager( "host_id", SHostwire{}, "hostwires_tbl", "hostwire", "hostwires", WireManager, ), } HostwireManager.SetVirtualObject(HostwireManager) }) } type SHostwire struct { SHostJointsBase Bridge string `width:"16" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"admin_required"` // 接口名称 Interface string `width:"16" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"admin_required"` // 是否是主地址 IsMaster bool `nullable:"true" default:"false" list:"admin" update:"admin" create:"admin_optional"` // MAC地址 MacAddr string `width:"18" charset:"ascii" list:"admin" update:"admin" create:"admin_required"` // 宿主机Id HostId string `width:"128" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"` // 二层网络Id WireId string `width:"128" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"` } func (manager *SHostwireManager) GetMasterFieldName() string { return "host_id" } func (manager *SHostwireManager) GetSlaveFieldName() string { return "wire_id" } func (joint *SHostwire) Master() db.IStandaloneModel { return db.JointMaster(joint) } func (joint *SHostwire) Slave() db.IStandaloneModel { return db.JointSlave(joint) } func (self *SHostwire) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.HostwireDetails, error) { return api.HostwireDetails{}, nil } func (manager *SHostwireManager) FetchCustomizeColumns( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool, ) []api.HostwireDetails { rows := make([]api.HostwireDetails, len(objs)) hostRows := manager.SHostJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) wireIds := make([]string, len(rows)) for i := range rows { rows[i] = api.HostwireDetails{ HostJointResourceDetails: hostRows[i], } wireIds[i] = objs[i].(*SHostwire).WireId } wires := make(map[string]SWire) err := db.FetchStandaloneObjectsByIds(WireManager, wireIds, &wires) if err != nil { log.Errorf("db.FetchStandaloneObjectsByIds fail %s", err) return rows } for i := range rows { if wire, ok := wires[wireIds[i]]; ok { rows[i].Wire = wire.Name rows[i].Bandwidth = wire.Bandwidth } } return rows } func (hw *SHostwire) GetWire() *SWire { wire, _ := WireManager.FetchById(hw.WireId) if wire != nil { return wire.(*SWire) } return nil } func (hw *SHostwire) GetHost() *SHost { host, _ := HostManager.FetchById(hw.HostId) if host != nil { return host.(*SHost) } return nil } func (self *SHostwire) GetGuestnicsCount() (int, error) { guestnics := GuestnetworkManager.Query().SubQuery() guests := GuestManager.Query().SubQuery() nets := NetworkManager.Query().SubQuery() q := guestnics.Query() q = q.Join(guests, sqlchemy.AND(sqlchemy.IsFalse(guests.Field("deleted")), sqlchemy.Equals(guests.Field("id"), guestnics.Field("guest_id")), sqlchemy.Equals(guests.Field("host_id"), self.HostId))) q = q.Join(nets, sqlchemy.AND(sqlchemy.IsFalse(nets.Field("deleted")), sqlchemy.Equals(nets.Field("id"), guestnics.Field("network_id")), sqlchemy.Equals(nets.Field("wire_id"), self.WireId))) return q.CountWithError() } func (self *SHostwire) ValidateDeleteCondition(ctx context.Context) error { cnt, err := self.GetGuestnicsCount() if err != nil { return httperrors.NewInternalServerError("GetGuestnicsCount fail %s", err) } if cnt > 0 { return httperrors.NewNotEmptyError("guest on the host are using networks on this wire") } return self.SHostJointsBase.ValidateDeleteCondition(ctx) } func (self *SHostwire) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { return db.DeleteModel(ctx, userCred, self) } func (self *SHostwire) Detach(ctx context.Context, userCred mcclient.TokenCredential) error { return db.DetachJoint(ctx, userCred, self) } func (manager *SHostwireManager) FilterByParams(q *sqlchemy.SQuery, params jsonutils.JSONObject) *sqlchemy.SQuery { macStr := jsonutils.GetAnyString(params, []string{"mac", "mac_addr"}) if len(macStr) > 0 { q = q.Filter(sqlchemy.Equals(q.Field("mac_addr"), macStr)) } return q } func (manager *SHostwireManager) FetchByHostIdAndMac(hostId string, mac string) (*SHostwire, error) { hw, err := db.NewModelObject(manager) if err != nil { return nil, err } q := manager.Query().Equals("host_id", hostId).Equals("mac_addr", mac) err = q.First(hw) if err != nil { return nil, err } return hw.(*SHostwire), nil } func (manager *SHostwireManager) ListItemFilter( ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.HostwireListInput, ) (*sqlchemy.SQuery, error) { var err error q, err = manager.SHostJointsManager.ListItemFilter(ctx, q, userCred, query.HostJointsListInput) if err != nil { return nil, errors.Wrap(err, "SHostResourceBaseManager.ListItemFilter") } q, err = manager.SWireResourceBaseManager.ListItemFilter(ctx, q, userCred, query.WireFilterListInput) if err != nil { return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter") } if len(query.Bridge) > 0 { q = q.In("bridge", query.Bridge) } if len(query.Interface) > 0 { q = q.In("interface", query.Interface) } if query.IsMaster != nil { if *query.IsMaster { q = q.IsTrue("is_master") } else { q = q.IsFalse("is_master") } } if len(query.MacAddr) > 0 { q = q.In("mac_addr", query.MacAddr) } return q, nil } func (manager *SHostwireManager) OrderByExtraFields( ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.HostwireListInput, ) (*sqlchemy.SQuery, error) { var err error q, err = manager.SHostJointsManager.OrderByExtraFields(ctx, q, userCred, query.HostJointsListInput) if err != nil { return nil, errors.Wrap(err, "SHostResourceBaseManager.OrderByExtraFields") } q, err = manager.SWireResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.WireFilterListInput) if err != nil { return nil, errors.Wrap(err, "SWireResourceBaseManager.OrderByExtraFields") } return q, nil }