feat(region): guestnetwork port mappings (#20516)

This commit is contained in:
Zexi Li
2024-06-11 18:17:10 +08:00
committed by GitHub
parent a62f9b8486
commit 66b9bb3441
13 changed files with 453 additions and 32 deletions

View File

@@ -113,6 +113,8 @@ type NetworkConfig struct {
StandbyPortCount int `json:"standby_port_count"`
StandbyAddrCount int `json:"standby_addr_count"`
PortMappings GuestPortMappings `json:"port_mappings"`
// swagger:ignore
Project string `json:"project_id"`

View File

@@ -15,8 +15,11 @@
package compute
import (
"reflect"
"yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/gotypes"
)
type GuestnetworkDetails struct {
@@ -125,7 +128,8 @@ type GuestnetworkBaseDesc struct {
Networkaddresses jsonutils.JSONObject `json:"networkaddresses"`
VirtualIps []string `json:"virtual_ips"`
VirtualIps []string `json:"virtual_ips"`
PortMappings GuestPortMappings `json:"port_mappings"`
}
type GuestnetworkJsonDesc struct {
@@ -155,3 +159,46 @@ type SNicTrafficRecord struct {
HasBeenSetDown bool
}
type GuestPortMappingProtocol string
const (
GuestPortMappingProtocolTCP GuestPortMappingProtocol = "tcp"
GuestPortMappingProtocolUDP GuestPortMappingProtocol = "udp"
)
const (
GUEST_PORT_MAPPING_RANGE_START = 20000
GUEST_PORT_MAPPING_RANGE_END = 25000
)
type GuestPortMappingPortRange struct {
Start int `json:"start"`
End int `json:"end"`
}
type GuestPortMapping struct {
Protocol GuestPortMappingProtocol `json:"protocol"`
Port int `json:"port"`
HostPort *int `json:"host_port,omitempty"`
HostIp string `json:"host_ip"`
HostPortRange *GuestPortMappingPortRange `json:"host_port_range,omitempty"`
// whitelist for remote ips
RemoteIps []string `json:"remote_ips"`
}
type GuestPortMappings []*GuestPortMapping
func (g GuestPortMappings) String() string {
return jsonutils.Marshal(g).String()
}
func (g GuestPortMappings) IsZero() bool {
return len(g) == 0
}
func init() {
gotypes.RegisterSerializable(reflect.TypeOf(&GuestPortMappings{}), func() gotypes.ISerializable {
return &GuestPortMappings{}
})
}

View File

@@ -71,9 +71,9 @@ type PodSecurityContext struct {
}
type PodCreateInput struct {
Containers []*PodContainerCreateInput `json:"containers"`
PortMappings []*PodPortMapping `json:"port_mappings"`
SecurityContext *PodSecurityContext `json:"security_context,omitempty"`
Containers []*PodContainerCreateInput `json:"containers"`
//PortMappings []*PodPortMapping `json:"port_mappings"`
SecurityContext *PodSecurityContext `json:"security_context,omitempty"`
}
type PodStartResponse struct {

View File

@@ -346,6 +346,88 @@ func ParseNetworkConfig(desc string, idx int) (*compute.NetworkConfig, error) {
return netConfig, nil
}
func ParseNetworkConfigPortMappings(descs []string) (map[int]compute.GuestPortMappings, error) {
if len(descs) == 0 {
return nil, ErrorEmptyDesc
}
pms := make(map[int]compute.GuestPortMappings, 0)
for _, desc := range descs {
idx, pm, err := parseNetworkConfigPortMapping(desc)
if err != nil {
return nil, errors.Wrapf(err, "parse port mapping: %s", desc)
}
mappings, ok := pms[idx]
if !ok {
mappings = make([]*compute.GuestPortMapping, 0)
}
mappings = append(mappings, pm)
pms[idx] = mappings
}
return pms, nil
}
func parseNetworkConfigPortMapping(desc string) (int, *compute.GuestPortMapping, error) {
pm := &compute.GuestPortMapping{
Protocol: compute.GuestPortMappingProtocolTCP,
}
idx := 0
for _, seg := range strings.Split(desc, ",") {
info := strings.Split(seg, "=")
if len(info) != 2 {
return -1, nil, errors.Errorf("invalid option %s", seg)
}
key := info[0]
val := info[1]
switch key {
case "index":
valIdx, err := strconv.Atoi(val)
if err != nil {
return -1, nil, errors.Wrapf(err, "invalid index %s", val)
}
idx = valIdx
case "host_port":
hp, err := strconv.Atoi(val)
if err != nil {
return -1, nil, errors.Wrapf(err, "invalid host_port %s", val)
}
pm.HostPort = &hp
case "container_port", "port":
cp, err := strconv.Atoi(val)
if err != nil {
return -1, nil, errors.Wrapf(err, "invalid container_port %s", val)
}
pm.Port = cp
case "proto", "protocol":
pm.Protocol = compute.GuestPortMappingProtocol(val)
case "host_port_range":
rangeParts := strings.Split(val, "-")
if len(rangeParts) != 2 {
return -1, nil, errors.Errorf("invalid range string %s", val)
}
start, err := strconv.Atoi(rangeParts[0])
if err != nil {
return -1, nil, errors.Wrapf(err, "invalid host_port_range %s", rangeParts[0])
}
end, err := strconv.Atoi(rangeParts[1])
if err != nil {
return -1, nil, errors.Wrapf(err, "invalid host_port_range %s", rangeParts[1])
}
pm.HostPortRange = &compute.GuestPortMappingPortRange{
Start: start,
End: end,
}
}
}
if pm.Port == 0 {
return -1, nil, errors.Error("container_port must specified")
}
if idx < 0 {
return -1, nil, errors.Errorf("invalid index %d", idx)
}
return idx, pm, nil
}
func ParseIsolatedDevice(desc string, idx int) (*compute.IsolatedDeviceConfig, error) {
if len(desc) == 0 {
return nil, ErrorEmptyDesc

View File

@@ -82,9 +82,9 @@ func (p *SPodDriver) ValidateCreateData(ctx context.Context, userCred mcclient.T
return nil, httperrors.NewNotEmptyError("containers data is empty")
}
// validate port mappings
if err := p.validatePortMappings(input.Pod); err != nil {
/*if err := p.validatePortMappings(input.Pod); err != nil {
return nil, errors.Wrap(err, "validate port mappings")
}
}*/
sameName := ""
for idx, ctr := range input.Pod.Containers {
@@ -100,7 +100,7 @@ func (p *SPodDriver) ValidateCreateData(ctx context.Context, userCred mcclient.T
return input, nil
}
func (p *SPodDriver) validatePortMappings(input *api.PodCreateInput) error {
/*func (p *SPodDriver) validatePortMappings(input *api.PodCreateInput) error {
usedPorts := make(map[api.PodPortMappingProtocol]sets.Int)
for idx, pm := range input.PortMappings {
ports, ok := usedPorts[pm.Protocol]
@@ -119,7 +119,7 @@ func (p *SPodDriver) validatePortMappings(input *api.PodCreateInput) error {
}
}
return nil
}
}*/
func (p *SPodDriver) validateHostPortMapping(hostId string, pm *api.PodPortMapping) error {
// TODO:

View File

@@ -118,6 +118,8 @@ type SGuestnetwork struct {
// 是否为缺省路由
IsDefault bool `default:"false" list:"user"`
PortMappings api.GuestPortMappings `length:"long" list:"user" update:"user"`
}
func (gn SGuestnetwork) GetIP() string {
@@ -263,7 +265,8 @@ type newGuestNetworkArgs struct {
rxTrafficLimit int64
txTrafficLimit int64
virtual bool
virtual bool
portMappings api.GuestPortMappings
}
func (manager *SGuestnetworkManager) newGuestNetwork(
@@ -310,6 +313,7 @@ func (manager *SGuestnetworkManager) newGuestNetwork(
if bwLimit >= 0 {
gn.BwLimit = bwLimit
}
gn.PortMappings = args.portMappings
lockman.LockObject(ctx, network)
defer lockman.ReleaseObject(ctx, network)
@@ -629,7 +633,8 @@ func (gn *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc {
Mac: gn.MacAddr,
Virtual: gn.Virtual,
IsDefault: gn.IsDefault,
IsDefault: gn.IsDefault,
PortMappings: gn.PortMappings,
},
}
@@ -746,6 +751,14 @@ func (gn *SGuestnetwork) UpdateNicTrafficLimit(rx, tx *int64) error {
return err
}
func (gn *SGuestnetwork) UpdatePortMappings(pms api.GuestPortMappings) error {
_, err := db.Update(gn, func() error {
gn.PortMappings = pms
return nil
})
return err
}
func (manager *SGuestnetworkManager) GetGuestByAddress(address string, projectId string) *SGuest {
gnQ := manager.Query()
ipField := "ip_addr"

View File

@@ -3495,7 +3495,8 @@ type Attach2NetworkArgs struct {
Virtual bool
IsDefault bool
IsDefault bool
PortMappings api.GuestPortMappings
PendingUsage quotas.IQuota
}
@@ -3527,6 +3528,7 @@ func (args *Attach2NetworkArgs) onceArgs(i int) attach2NetworkOnceArgs {
isDefault: args.IsDefault,
pendingUsage: args.PendingUsage,
portMappings: args.PortMappings,
}
if i > 0 {
r.ipAddr = ""
@@ -3569,6 +3571,7 @@ type attach2NetworkOnceArgs struct {
isDefault bool
pendingUsage quotas.IQuota
portMappings api.GuestPortMappings
}
func (self *SGuest) Attach2Network(
@@ -3644,7 +3647,8 @@ func (self *SGuest) attach2NetworkOnce(
virtual: args.virtual,
isDefault: args.isDefault,
isDefault: args.isDefault,
portMappings: args.portMappings,
}
lockman.LockClass(ctx, QuotaManager, self.ProjectId)
defer lockman.ReleaseClass(ctx, QuotaManager, self.ProjectId)
@@ -4416,7 +4420,8 @@ func (self *SGuest) attach2NamedNetworkDesc(ctx context.Context, userCred mcclie
UseDesignatedIP: reuseAddr,
NicConfs: nicConfs,
IsDefault: netConfig.IsDefault,
IsDefault: netConfig.IsDefault,
PortMappings: netConfig.PortMappings,
})
if err != nil {
return nil, errors.Wrap(err, "Attach2Network fail")

View File

@@ -35,6 +35,7 @@ import (
"yunion.io/x/pkg/util/rand"
"yunion.io/x/pkg/util/rbacscope"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/util/sets"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -1189,6 +1190,63 @@ func isValidNetworkInfo(ctx context.Context, userCred mcclient.TokenCredential,
ct, ctExit := NetworkManager.to
}
*/
if len(netConfig.PortMappings) != 0 {
for i := range netConfig.PortMappings {
if err := validatePortMapping(netConfig.PortMappings[i]); err != nil {
return errors.Wrapf(err, "validate port mapping %s", jsonutils.Marshal(netConfig.PortMappings[i]))
}
}
}
return nil
}
func validatePortRange(portRange *api.GuestPortMappingPortRange) error {
if portRange != nil {
if portRange.Start > portRange.End {
return httperrors.NewInputParameterError("port range start %d is large than %d", portRange.Start, portRange.End)
}
if portRange.Start <= api.GUEST_PORT_MAPPING_RANGE_START {
return httperrors.NewInputParameterError("port range start %d <= %d", api.GUEST_PORT_MAPPING_RANGE_START, portRange.Start)
}
if portRange.End > api.GUEST_PORT_MAPPING_RANGE_END {
return httperrors.NewInputParameterError("port range end %d > %d", api.GUEST_PORT_MAPPING_RANGE_END, portRange.End)
}
}
return nil
}
func validatePort(port int, start int, end int) error {
if port < start || port > end {
return httperrors.NewInputParameterError("port number %d isn't within %d to %d", port, start, end)
}
return nil
}
func validatePortMapping(pm *api.GuestPortMapping) error {
if err := validatePortRange(pm.HostPortRange); err != nil {
return err
}
if pm.HostPort != nil {
if err := validatePort(*pm.HostPort, api.GUEST_PORT_MAPPING_RANGE_START, api.GUEST_PORT_MAPPING_RANGE_END); err != nil {
return errors.Wrap(err, "validate host_port")
}
}
if err := validatePort(pm.Port, 1, 65535); err != nil {
return errors.Wrap(err, "validate port")
}
if pm.Protocol == "" {
pm.Protocol = api.GuestPortMappingProtocolTCP
}
if !sets.NewString(string(api.GuestPortMappingProtocolUDP), string(api.GuestPortMappingProtocolTCP)).Has(string(pm.Protocol)) {
return httperrors.NewInputParameterError("unsupported protocol %s", pm.Protocol)
}
if len(pm.RemoteIps) != 0 {
for _, ip := range pm.RemoteIps {
if !regutils.MatchIPAddr(ip) {
return httperrors.NewInputParameterError("invalid ip %s", ip)
}
}
}
return nil
}

View File

@@ -790,6 +790,11 @@ func (m *SGuestManager) startDeploy(
return nil, errors.Errorf("missing telegraf_conf")
}
// refresh port_mappings
if err := NewPortMappingManager(m).AllocateGuestPortMappings(ctx, deployParams.UserCred, guest); err != nil {
return nil, errors.Wrap(err, "allocate port mappings")
}
guestInfo, err := guest.DeployFs(ctx, deployParams.UserCred,
deployapi.NewDeployInfo(
publicKey, deployArray,

View File

@@ -160,7 +160,7 @@ func (s *sPodGuestInstance) SyncStatus(reason string) {
func (s *sPodGuestInstance) DeployFs(ctx context.Context, userCred mcclient.TokenCredential, deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
// update port_mappings
podInput, err := s.getPodCreateParams()
/*podInput, err := s.getPodCreateParams()
if err != nil {
return nil, errors.Wrap(err, "getPodCreateParams")
}
@@ -172,7 +172,7 @@ func (s *sPodGuestInstance) DeployFs(ctx context.Context, userCred mcclient.Toke
if err := s.setPortMappings(ctx, userCred, s.convertToPodMetadataPortMappings(pms)); err != nil {
return nil, errors.Wrap(err, "set port mappings")
}
}
}*/
return nil, nil
}
@@ -547,7 +547,7 @@ func (s *sPodGuestInstance) startPod(ctx context.Context, userCred mcclient.Toke
}
}
metaPms, err := s.GetPodMetadataPortMappings()
/*metaPms, err := s.GetPodMetadataPortMappings()
if err != nil {
return nil, errors.Wrap(err, "GetPodMetadataPortMappings")
}
@@ -570,7 +570,7 @@ func (s *sPodGuestInstance) startPod(ctx context.Context, userCred mcclient.Toke
}
}
podCfg.PortMappings = pms
}
}*/
criId, err := s.getCRI().RunPod(ctx, podCfg, "")
if err != nil {

View File

@@ -0,0 +1,195 @@
package guestman
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/sets"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
computemod "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
"yunion.io/x/onecloud/pkg/util/netutils2/getport"
)
type IPortMappingManager interface {
AllocateGuestPortMappings(ctx context.Context, userCred mcclient.TokenCredential, guest GuestRuntimeInstance) error
}
type portMappingManager struct {
manager *SGuestManager
}
func NewPortMappingManager(manager *SGuestManager) IPortMappingManager {
return &portMappingManager{
manager: manager,
}
}
func (m *portMappingManager) GetGuestPortMappings(guest GuestRuntimeInstance) map[string]compute.GuestPortMappings {
nics := guest.GetSourceDesc().Nics
pms := make(map[string]compute.GuestPortMappings)
for _, nic := range nics {
if len(nic.PortMappings) == 0 {
continue
}
pms[nic.NetId] = nic.PortMappings
}
return pms
}
func (m *portMappingManager) IsGuestHasPortMapping(guest GuestRuntimeInstance) bool {
return len(m.GetGuestPortMappings(guest)) == 0
}
func (m *portMappingManager) AllocateGuestPortMappings(ctx context.Context, userCred mcclient.TokenCredential, guest GuestRuntimeInstance) error {
for idx, nic := range guest.GetDesc().Nics {
if len(nic.PortMappings) == 0 {
continue
}
newPms, err := m.allocatePortMappings(guest, nic.PortMappings)
if err != nil {
return errors.Wrapf(err, "allocateGuestPortMapping for nic %d: %s", idx, jsonutils.Marshal(nic.PortMappings))
}
// update allocated port mappings
if err := m.setPortMappings(ctx, userCred, guest, idx, newPms); err != nil {
return errors.Wrapf(err, "setPortMappings for nic %d", idx)
}
}
return nil
}
func (m *portMappingManager) setPortMappings(ctx context.Context, userCred mcclient.TokenCredential, gst GuestRuntimeInstance, nicIdx int, pms compute.GuestPortMappings) error {
// update desc
desc := gst.GetDesc()
nic := desc.Nics[nicIdx]
nic.PortMappings = pms
desc.Nics[nicIdx] = nic
// update port mapping info to controller
body := jsonutils.Marshal(map[string]interface{}{
"port_mappings": pms,
})
session := auth.GetSession(ctx, userCred, options.HostOptions.Region)
if _, err := computemod.Servernetworks.Update(session, gst.GetId(), nic.NetId, nil, body); err != nil {
return errors.Wrapf(err, "update server %s network %s with port_mappings %s", gst.GetId(), nic.NetId, body.String())
}
// save desc
gst.SetDesc(desc)
return SaveDesc(gst, desc)
}
func (m *portMappingManager) getOtherGuests(gst GuestRuntimeInstance) []GuestRuntimeInstance {
others := make([]GuestRuntimeInstance, 0)
m.manager.Servers.Range(func(id, value interface{}) bool {
if id == gst.GetId() {
return true
}
ins := value.(GuestRuntimeInstance)
others = append(others, ins)
return true
})
return others
}
func (m *portMappingManager) getGuestFlattenPortMappings(guest GuestRuntimeInstance) compute.GuestPortMappings {
ret := make([]*compute.GuestPortMapping, 0)
pms := m.GetGuestPortMappings(guest)
for _, pm := range pms {
for _, p := range pm {
ret = append(ret, p)
}
}
return ret
}
func (m *portMappingManager) getOtherGuestsUsedPorts(gst GuestRuntimeInstance) (map[compute.GuestPortMappingProtocol]sets.Int, error) {
others := m.getOtherGuests(gst)
ret := make(map[compute.GuestPortMappingProtocol]sets.Int)
for _, ins := range others {
pms := m.getGuestFlattenPortMappings(ins)
for _, pm := range pms {
ps, ok := ret[pm.Protocol]
if !ok {
ps = sets.NewInt()
}
if pm.HostPort == nil {
return nil, errors.Errorf("portmap %s has nil host port", jsonutils.Marshal(pm))
}
ps.Insert(*pm.HostPort)
ret[pm.Protocol] = ps
}
}
return ret, nil
}
func (m *portMappingManager) allocatePortMappings(gst GuestRuntimeInstance, input compute.GuestPortMappings) (compute.GuestPortMappings, error) {
result := make([]*compute.GuestPortMapping, len(input))
for idx := range input {
pm, err := m.allocatePortMapping(gst, input[idx])
if err != nil {
return nil, errors.Wrapf(err, "get port mapping %s", jsonutils.Marshal(input[idx]))
}
result[idx] = pm
}
return result, nil
}
func (m *portMappingManager) allocatePortMapping(gst GuestRuntimeInstance, pm *compute.GuestPortMapping) (*compute.GuestPortMapping, error) {
otherPorts, err := m.getOtherGuestsUsedPorts(gst)
if err != nil {
return nil, errors.Wrap(err, "getOtherPodsUsedPorts")
}
// copy to runtime port mapping
runtimePm := &compute.GuestPortMapping{}
if err := jsonutils.Marshal(pm).Unmarshal(runtimePm); err != nil {
return nil, errors.Wrap(err, "unmarshal to runtime port mapping")
}
portProtocol := getport.TCP
switch pm.Protocol {
case compute.GuestPortMappingProtocolTCP:
portProtocol = getport.TCP
case compute.GuestPortMappingProtocolUDP:
portProtocol = getport.UDP
default:
return nil, errors.Errorf("invalid protocol: %q", pm.Protocol)
}
if pm.HostPort != nil {
runtimePm.HostPort = pm.HostPort
if getport.IsPortUsed(portProtocol, "", *pm.HostPort) {
return nil, httperrors.NewInputParameterError("host_port %d is used", *pm.HostPort)
}
usedPorts, ok := otherPorts[pm.Protocol]
if ok {
if usedPorts.Has(*pm.HostPort) {
return nil, errors.Errorf("%s host_port %d is already used", pm.Protocol, *pm.HostPort)
}
}
return runtimePm, nil
} else {
start := compute.GUEST_PORT_MAPPING_RANGE_START
end := compute.GUEST_PORT_MAPPING_RANGE_END
if pm.HostPortRange != nil {
start = pm.HostPortRange.Start
end = pm.HostPortRange.End
}
otherPodPorts, ok := otherPorts[pm.Protocol]
if !ok {
otherPodPorts = sets.NewInt()
}
portResult, err := getport.GetPortByRangeBySets(portProtocol, start, end, otherPodPorts)
if err != nil {
return nil, errors.Wrapf(err, "listen %s port inside %d and %d", pm.Protocol, start, end)
}
runtimePm.HostPort = &portResult.Port
return runtimePm, nil
}
}

View File

@@ -31,14 +31,14 @@ import (
type PodCreateOptions struct {
NAME string `help:"Name of server pod" json:"-"`
ServerCreateCommonConfig
MEM string `help:"Memory size MB" metavar:"MEM" json:"-"`
VcpuCount int `help:"#CPU cores of VM server, default 1" default:"1" metavar:"<SERVER_CPU_COUNT>" json:"vcpu_count" token:"ncpu"`
AllowDelete *bool `help:"Unlock server to allow deleting" json:"-"`
PortMapping []string `help:"Port mapping of the pod and the format is: host_port=8080,port=80,protocol=<tcp|udp>,host_port_range=<int>-<int>" short-token:"p"`
Arch string `help:"image arch" choices:"aarch64|x86_64"`
AutoStart bool `help:"Auto start server after it is created"`
PodUid int64 `help:"UID of pod" default:"0"`
PodGid int64 `help:"GID of pod" default:"0"`
MEM string `help:"Memory size MB" metavar:"MEM" json:"-"`
VcpuCount int `help:"#CPU cores of VM server, default 1" default:"1" metavar:"<SERVER_CPU_COUNT>" json:"vcpu_count" token:"ncpu"`
AllowDelete *bool `help:"Unlock server to allow deleting" json:"-"`
//PortMapping []string `help:"Port mapping of the pod and the format is: host_port=8080,port=80,protocol=<tcp|udp>,host_port_range=<int>-<int>" short-token:"p"`
Arch string `help:"image arch" choices:"aarch64|x86_64"`
AutoStart bool `help:"Auto start server after it is created"`
PodUid int64 `help:"UID of pod" default:"0"`
PodGid int64 `help:"GID of pod" default:"0"`
ContainerCreateCommonOptions
}
@@ -182,7 +182,7 @@ func (o *PodCreateOptions) Params() (*computeapi.ServerCreateInput, error) {
}
config.Hypervisor = computeapi.HYPERVISOR_POD
portMappings := make([]*computeapi.PodPortMapping, 0)
/*portMappings := make([]*computeapi.PodPortMapping, 0)
if len(o.PortMapping) != 0 {
for _, input := range o.PortMapping {
pm, err := ParsePodPortMapping(input)
@@ -191,7 +191,7 @@ func (o *PodCreateOptions) Params() (*computeapi.ServerCreateInput, error) {
}
portMappings = append(portMappings, pm)
}
}
}*/
spec, err := o.getCreateSpec()
if err != nil {
@@ -203,7 +203,7 @@ func (o *PodCreateOptions) Params() (*computeapi.ServerCreateInput, error) {
VcpuCount: o.VcpuCount,
AutoStart: o.AutoStart,
Pod: &computeapi.PodCreateInput{
PortMappings: portMappings,
//PortMappings: portMappings,
Containers: []*computeapi.PodContainerCreateInput{
{
ContainerSpec: *spec,

View File

@@ -15,13 +15,13 @@
package compute
import (
"errors"
"fmt"
"io/ioutil"
"strconv"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/fileutils"
"yunion.io/x/pkg/util/regutils"
@@ -32,7 +32,7 @@ import (
"yunion.io/x/onecloud/pkg/util/cgrouputils"
)
var ErrEmtptyUpdate = errors.New("No valid update data")
var ErrEmtptyUpdate = errors.Error("No valid update data")
type ServerListOptions struct {
Zone string `help:"Zone ID or Name"`
@@ -252,6 +252,7 @@ type ServerCreateCommonConfig struct {
ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"`
Schedtag []string `help:"Schedule policy, key = aggregate name, value = require|exclude|prefer|avoid" metavar:"<KEY:VALUE>"`
Net []string `help:"Network descriptions" metavar:"NETWORK"`
NetPortMapping []string `help:"Network port mapping, e.g. 'index=0,port=80,host_port=8080,protocol=<tcp|udp>,host_port_range=<int>-<int>,remote_ips=x.x.x.x|y.y.y.y'" short-token:"p"`
NetSchedtag []string `help:"Network schedtag description, e.g. '0:<tag>:<strategy>'"`
IsolatedDevice []string `help:"Isolated device model or ID" metavar:"ISOLATED_DEVICE"`
Project string `help:"'Owner project ID or Name" json:"tenant"`
@@ -299,6 +300,19 @@ func (o ServerCreateCommonConfig) Data() (*computeapi.ServerConfigs, error) {
}
data.Networks = append(data.Networks, net)
}
if len(o.NetPortMapping) != 0 {
pms, err := cmdline.ParseNetworkConfigPortMappings(o.NetPortMapping)
if err != nil {
return nil, errors.Wrap(err, "parse network port mapping")
}
for idx, _ := range pms {
if idx >= len(data.Networks) {
return nil, errors.Errorf("not found %d network of index", idx)
}
pm := pms[idx]
data.Networks[idx].PortMappings = pm
}
}
for _, ntag := range o.NetSchedtag {
idx, tag, err := cmdline.ParseResourceSchedtagConfig(ntag)
if err != nil {
@@ -1459,7 +1473,7 @@ func (o *ServerCPUSetOptions) Params() (jsonutils.JSONObject, error) {
sets := cgrouputils.ParseCpusetStr(o.SETS)
parts := strings.Split(sets, ",")
if len(parts) == 0 {
return nil, errors.New(fmt.Sprintf("Invalid cpu sets %q", o.SETS))
return nil, errors.Error(fmt.Sprintf("Invalid cpu sets %q", o.SETS))
}
input := &computeapi.ServerCPUSetInput{
CPUS: make([]int, 0),
@@ -1467,7 +1481,7 @@ func (o *ServerCPUSetOptions) Params() (jsonutils.JSONObject, error) {
for _, s := range parts {
sd, err := strconv.Atoi(s)
if err != nil {
return nil, errors.New(fmt.Sprintf("Not digit part %q", s))
return nil, errors.Wrapf(err, "Not digit part %q", s)
}
input.CPUS = append(input.CPUS, sd)
}