diff --git a/cmd/climc/shell/networks.go b/cmd/climc/shell/networks.go index aec9e62a33..b101d686fd 100644 --- a/cmd/climc/shell/networks.go +++ b/cmd/climc/shell/networks.go @@ -210,6 +210,7 @@ func init() { NETMASK int64 `help:"Length of network mask"` Gateway string `help:"Default gateway"` VlanId int64 `help:"Vlan ID" default:"1"` + IfnameHint string `help:"Hint for ifname generation"` AllocPolicy string `help:"Address allocation policy" choices:"none|stepdown|stepup|random"` ServerType string `help:"Server type" choices:"baremetal|guest|container|pxe|ipmi"` Desc string `help:"Description" metavar:"DESCRIPTION"` @@ -229,6 +230,9 @@ func init() { if len(args.ServerType) > 0 { params.Add(jsonutils.NewString(args.ServerType), "server_type") } + if len(args.IfnameHint) > 0 { + params.Add(jsonutils.NewString(args.IfnameHint), "ifname_hint") + } if len(args.AllocPolicy) > 0 { params.Add(jsonutils.NewString(args.AllocPolicy), "alloc_policy") } diff --git a/pkg/compute/models/guestnetworks.go b/pkg/compute/models/guestnetworks.go index 2ddb7c44f6..28e5777d43 100644 --- a/pkg/compute/models/guestnetworks.go +++ b/pkg/compute/models/guestnetworks.go @@ -224,7 +224,7 @@ func (self *SGuestnetwork) getVirtualRand(width int, randomized bool) string { func (self *SGuestnetwork) generateIfname(network *SNetwork, virtual bool, randomized bool) string { pattern := regexp.MustCompile(`\W+`) - nName := pattern.ReplaceAllString(network.Name, "") + nName := pattern.ReplaceAllString(network.IfnameHint, "") if len(nName) > MAX_IFNAME_SIZE-4 { nName = nName[:(MAX_IFNAME_SIZE - 4)] } diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index e70e67d6a6..40d7548376 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -44,6 +44,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/rand" "yunion.io/x/onecloud/pkg/util/rbacutils" ) @@ -76,8 +77,6 @@ func init() { "networks", ), } - NetworkManager.NameLength = 9 - NetworkManager.NameRequireAscii = true NetworkManager.SetVirtualObject(NetworkManager) } @@ -85,6 +84,8 @@ type SNetwork struct { db.SSharableVirtualResourceBase db.SExternalizedResourceBase + IfnameHint string `width:"9" charset:"ascii" nullable:"false" list:"user" create:"optional"` + GuestIpStart string `width:"16" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` // Column(VARCHAR(16, charset='ascii'), nullable=False) GuestIpEnd string `width:"16" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` // Column(VARCHAR(16, charset='ascii'), nullable=False) GuestIpMask int8 `nullable:"false" list:"user" update:"user" create:"required"` // Column(TINYINT, nullable=False) @@ -1104,6 +1105,39 @@ func isValidMaskLen(maskLen int64) bool { } } +func (manager *SNetworkManager) newIfnameHint(hint string) (string, error) { + r := "" + // sanitize hint + for _, c := range hint { + if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' { + r += string(c) + } + } + newHint := func() (string, error) { + for i := 0; i < 3; i++ { + r := rand.String(7) + cnt, err := manager.Query().Equals("ifname_hint", r).CountWithError() + if err == nil && cnt == 0 { + return r, nil + } + } + return "", fmt.Errorf("failed finding ifname hint after 3 tries") + } + if len(r) < 3 { + return newHint() + } + if len(r) > 9 { + r = r[:9] + } + if cnt, err := manager.Query().Equals("ifname_hint", r).CountWithError(); err != nil { + return "", err + } else if cnt > 0 { + r, err := newHint() + return r, err + } + return r, nil +} + func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { prefixStr, _ := data.GetString("guest_ip_prefix") var maskLen64 int64 @@ -1143,6 +1177,18 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred data.Add(jsonutils.NewString(startIp.String()), "guest_ip_start") data.Add(jsonutils.NewString(endIp.String()), "guest_ip_end") + { + hint, _ := data.GetString("ifname_hint") + if hint == "" { + hint, _ = data.GetString("name") + } + hint, err = manager.newIfnameHint(hint) + if err != nil { + return nil, httperrors.NewBadRequestError("cannot derive valid ifname hint: %v", err) + } + data.Set("ifname_hint", jsonutils.NewString(hint)) + } + for _, key := range []string{"guest_gateway", "guest_dns", "guest_dhcp"} { ipStr, _ := data.GetString(key) if len(ipStr) > 0 && !regutils.MatchIPAddr(ipStr) { @@ -1700,9 +1746,26 @@ func (manager *SNetworkManager) InitializeData() error { return err } for _, n := range networks { - if len(n.ExternalId) == 0 && len(n.WireId) > 0 && n.Status == api.NETWORK_STATUS_INIT { + if n.ExternalId != "" { + var statusNew string + if n.WireId != "" && n.Status == api.NETWORK_STATUS_INIT { + statusNew = api.NETWORK_STATUS_AVAILABLE + } db.Update(&n, func() error { - n.Status = api.NETWORK_STATUS_AVAILABLE + if statusNew != "" { + n.Status = statusNew + } + return nil + }) + } else { + var ifnameHintNew string + if n.IfnameHint == "" { + ifnameHintNew = n.Name + } + db.Update(&n, func() error { + if ifnameHintNew != "" { + n.IfnameHint = ifnameHintNew + } return nil }) }