From 8684ba29b0de874bed0c0922934027f10dd1e75a Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Thu, 11 Jul 2019 20:55:33 +0800 Subject: [PATCH] auto create subnet on host register --- pkg/compute/models/networks.go | 111 +++++++++++++++++++++++++ pkg/hostman/hostinfo/hostinfo.go | 79 ++++++++++++++++-- pkg/hostman/hostinfo/hostinfohelper.go | 5 ++ 3 files changed, 187 insertions(+), 8 deletions(-) diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index 8cc12eae62..78112c8c76 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -1834,6 +1834,117 @@ func (self *SNetwork) PerformSplit(ctx context.Context, userCred mcclient.TokenC return nil, nil } +func (manager *SNetworkManager) AllowPerformTryCreateNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return db.IsAdminAllowClassPerform(userCred, manager, "try-create-network") +} + +func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + ip, err := data.GetString("ip") + if err != nil { + return nil, httperrors.NewMissingParameterError("ip") + } + ipV4, err := netutils.NewIPV4Addr(ip) + if err != nil { + return nil, httperrors.NewInputParameterError("ip") + } + mask, err := data.Int("mask") + if err != nil { + return nil, httperrors.NewMissingParameterError("mask") + } + serverType, err := data.GetString("server_type") + if err != nil { + return nil, httperrors.NewMissingParameterError("server_type") + } + if serverType != api.NETWORK_TYPE_BAREMETAL { + return nil, httperrors.NewBadRequestError("Only support server type %s", api.NETWORK_TYPE_BAREMETAL) + } + if !jsonutils.QueryBoolean(data, "is_on_premise", false) { + return nil, httperrors.NewBadRequestError("Only support on premise network") + } + + var ( + ipV4NetAddr = ipV4.NetAddr(int8(mask)) + nm *SNetwork + matched bool + ) + + q := NetworkManager.Query().Equals("server_type", serverType).Equals("guest_ip_mask", mask) + q = managedResourceFilterByCloudType(q, query, "wire_id", func() *sqlchemy.SQuery { + wires := WireManager.Query().SubQuery() + vpcs := VpcManager.Query().SubQuery() + subq := wires.Query(wires.Field("id")) + subq = subq.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) + return subq + }) + + rows, err := q.Rows() + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + item, err := db.NewModelObject(NetworkManager) + if err != nil { + return nil, err + } + err = q.Row2Struct(rows, item) + if err != nil { + return nil, err + } + n := item.(*SNetwork) + if n.GetIPRange().Contains(ipV4) { + nm = n + matched = true + break + } else if nIpV4, _ := netutils.NewIPV4Addr(n.GuestIpStart); nIpV4.NetAddr(n.GuestIpMask) == ipV4NetAddr { + nm = n + matched = false + break + } + } + + ret := jsonutils.NewDict() + if nm == nil { + ret.Set("find_matched", jsonutils.JSONFalse) + return ret, nil + } else { + ret.Set("find_matched", jsonutils.JSONTrue) + ret.Set("wire_id", jsonutils.NewString(nm.WireId)) + } + if !matched { + log.Infof("Find same subnet network %s %s/%d", nm.Name, nm.GuestGateway, nm.GuestIpMask) + newNetwork := new(SNetwork) + newNetwork.SetModelManager(NetworkManager, newNetwork) + newNetwork.GuestIpStart = ip + newNetwork.GuestIpEnd = ip + newNetwork.GuestGateway = nm.GuestGateway + newNetwork.GuestIpMask = int8(mask) + newNetwork.GuestDns = nm.GuestDns + newNetwork.GuestDhcp = nm.GuestDhcp + newNetwork.WireId = nm.WireId + newNetwork.ServerType = serverType + newNetwork.IsPublic = nm.IsPublic + newNetwork.ProjectId = userCred.GetProjectId() + newNetwork.DomainId = userCred.GetProjectDomainId() + newName, err := db.GenerateName(NetworkManager, userCred, fmt.Sprintf("%s#", nm.Name)) + if err != nil { + return nil, httperrors.NewInternalServerError("GenerateName fail %s", err) + } + newNetwork.Name = newName + + err = NetworkManager.TableSpec().Insert(newNetwork) + if err != nil { + return nil, err + } + err = newNetwork.CustomizeCreate(ctx, userCred, userCred, query, data) + if err != nil { + return nil, err + } + newNetwork.PostCreate(ctx, userCred, userCred, query, data) + } + return ret, nil +} + func (network *SNetwork) getAllocTimoutDuration() time.Duration { tos := network.AllocTimoutSeconds if tos < options.Options.MinimalIpAddrReusedIntervalSeconds { diff --git a/pkg/hostman/hostinfo/hostinfo.go b/pkg/hostman/hostinfo/hostinfo.go index 5038b6c6e6..00fda7784c 100644 --- a/pkg/hostman/hostinfo/hostinfo.go +++ b/pkg/hostman/hostinfo/hostinfo.go @@ -500,6 +500,19 @@ func (h *SHostInfo) detectiveOvsVersion() { } } +func (h *SHostInfo) GetMasterNicIpAndMask() (string, int) { + if h.MasterNic != nil { + mask, _ := h.MasterNic.Mask.Size() + return h.MasterNic.Addr, mask + } + for _, n := range h.Nics { + if len(n.Ip) > 0 { + return n.Ip, n.Mask + } + } + return "", 0 +} + func (h *SHostInfo) GetMasterIp() string { if h.MasterNic != nil { return h.MasterNic.Addr @@ -563,27 +576,76 @@ func (h *SHostInfo) onFail() { panic("register failed, try 30 seconds later...") } +// try to create network on region. +func (h *SHostInfo) tryCreateNetworkOnWire() { + masterIp, mask := h.GetMasterNicIpAndMask() + log.Debugf("Get master ip %s and mask %d", masterIp, mask) + if len(masterIp) == 0 || mask == 0 { + return + } + params := jsonutils.NewDict() + params.Set("ip", jsonutils.NewString(masterIp)) + params.Set("mask", jsonutils.NewInt(int64(mask))) + params.Set("is_on_premise", jsonutils.JSONTrue) + params.Set("server_type", jsonutils.NewString(api.NETWORK_TYPE_BAREMETAL)) + ret, err := modules.Networks.PerformClassAction( + hostutils.GetComputeSession(context.Background()), + "try-create-network", params) + if err != nil { + log.Errorf("try create network get error %s", err) + h.onFail() + } + if !jsonutils.QueryBoolean(ret, "find_matched", false) { + log.Errorf("Fail to get network info: no networks") + h.onFail() + } + wireId, err := ret.GetString("wire_id") + if err != nil { + log.Errorf("Fail to get network info: no wire id") + h.onFail() + } + h.onGetWireId(wireId) +} + func (h *SHostInfo) fetchAccessNetworkInfo() { masterIp := h.GetMasterIp() if len(masterIp) == 0 { panic("master ip not found") } + log.Debugf("Master ip %s to fetch wire", masterIp) params := jsonutils.NewDict() params.Set("ip", jsonutils.NewString(masterIp)) params.Set("is_on_premise", jsonutils.JSONTrue) params.Set("limit", jsonutils.NewInt(0)) - wire, err := hostutils.GetWireOfIp(context.Background(), params) + + res, err := modules.Networks.List(h.GetSession(), params) + if err != nil { + log.Errorln(err) + h.onFail() + } + if len(res.Data) == 0 { + h.tryCreateNetworkOnWire() + } else if len(res.Data) == 1 { + wireId, _ := res.Data[0].GetString("wire_id") + h.onGetWireId(wireId) + } else { + log.Errorf("Fail to get network info: no networks") + h.onFail() + } +} + +func (h *SHostInfo) onGetWireId(wireId string) { + wire, err := hostutils.GetWireInfo(context.Background(), wireId) + if err != nil { + log.Errorln(err) + h.onFail() + } + h.ZoneId, err = wire.GetString("zone_id") if err != nil { log.Errorln(err) h.onFail() } else { - h.ZoneId, err = wire.GetString("zone_id") - if err != nil { - log.Errorln(err) - h.onFail() - } else { - h.getZoneInfo(h.ZoneId, false) - } + h.getZoneInfo(h.ZoneId, false) } } @@ -592,6 +654,7 @@ func (h *SHostInfo) GetSession() *mcclient.ClientSession { } func (h *SHostInfo) getZoneInfo(zoneId string, standalone bool) { + log.Debugf("Start GetZoneInfo %s %v", zoneId, standalone) var params = jsonutils.NewDict() params.Set("standalone", jsonutils.NewBool(standalone)) res, err := modules.Zones.Get(h.GetSession(), diff --git a/pkg/hostman/hostinfo/hostinfohelper.go b/pkg/hostman/hostinfo/hostinfohelper.go index 3655957881..e72da00993 100644 --- a/pkg/hostman/hostinfo/hostinfohelper.go +++ b/pkg/hostman/hostinfo/hostinfohelper.go @@ -188,6 +188,7 @@ type SNIC struct { Ip string Network string WireId string + Mask int Bandwidth int BridgeDev hostbridge.IBridgeDriver @@ -250,6 +251,10 @@ func NewNIC(desc string) (*SNIC, error) { for wait < max { inf := netutils2.NewNetInterface(nic.Inter) if inf.Addr == nic.Ip { + mask, _ := inf.Mask.Size() + if mask > 0 { + nic.Mask = mask + } break } br := netutils2.NewNetInterface(nic.Bridge)