mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
feat(region): guestnetwork port mappings (#20516)
This commit is contained in:
@@ -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"`
|
||||
|
||||
|
||||
@@ -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{}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
195
pkg/hostman/guestman/portmapping.go
Normal file
195
pkg/hostman/guestman/portmapping.go
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user