Skip to content
This repository has been archived by the owner on Feb 8, 2021. It is now read-only.

Commit

Permalink
Merge pull request #652 from gnawux/portmapping
Browse files Browse the repository at this point in the history
pod level port-mapping support
  • Loading branch information
bergwolf authored Sep 28, 2017
2 parents f0c8bb2 + 5453b70 commit 20ab5d6
Show file tree
Hide file tree
Showing 36 changed files with 2,863 additions and 476 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ if ON_DARWIN
SUBDIRS=mac_installer
endif

VERSION_PARAM=-ldflags "-X github.com/hyperhq/hyperd/utils.VERSION=$(VERSION) -X github.com/hyperhq/hyperd/utils.GITCOMMIT=`git describe`"
VERSION_PARAM=-ldflags "-X github.com/hyperhq/hyperd/utils.VERSION=$(VERSION) -X github.com/hyperhq/hyperd/utils.GITCOMMIT=`git describe --dirty --always --tags 2> /dev/null || true`"

all-local: build-hyperd build-hyperctl build-vmlogd
clean-local:
Expand Down
5 changes: 5 additions & 0 deletions client/api/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ type APIInterface interface {
UnpausePod(podId string) error
KillPod(pod string, sig int) error

// PortMapping APIs
ListPortMappings(podId string) ([]*types.PortMapping, error)
AddPortMappings(podId string, pms []*types.PortMapping) error
DeletePortMappings(podId string, pms []*types.PortMapping) error

Build(name string, hasBody bool, body io.Reader) (io.ReadCloser, string, error)
Commit(container, repo, author, message string, changes []string, pause bool) (string, error)
Load(body io.Reader, name string, refs map[string]string) (io.ReadCloser, string, error)
Expand Down
62 changes: 62 additions & 0 deletions client/api/portmapping.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package api

import (
"encoding/json"
"fmt"
"net/http"

"github.com/hyperhq/hyperd/types"
)

type PortMappingList struct {
PortMappings []*types.PortMapping `json:"portMappings"`
}

func (c *Client) ListPortMappings(podId string) ([]*types.PortMapping, error) {
path := fmt.Sprintf("/pod/%s/portmappings", podId)

body, code, err := readBody(c.call("GET", path, nil, nil))
if code == http.StatusNotFound {
return nil, fmt.Errorf("pod %s not found", podId)
} else if err != nil {
return nil, err
}

var pms PortMappingList
err = json.Unmarshal(body, &pms)
if err != nil {
return nil, err
}

return pms.PortMappings, nil
}

func (c *Client) AddPortMappings(podId string, pms []*types.PortMapping) error {
path := fmt.Sprintf("/pod/%s/portmappings/add", podId)
r, code, err := readBody(c.call("PUT", path, pms, nil))

if code == http.StatusNoContent || code == http.StatusOK {
return nil
} else if code == http.StatusNotFound {
return fmt.Errorf("pod %s not found", podId)
} else if err != nil {
return err
} else {
return fmt.Errorf("unexpect response code %d: %s", code, string(r))
}
}

func (c *Client) DeletePortMappings(podId string, pms []*types.PortMapping) error {
path := fmt.Sprintf("/pod/%s/portmappings/delete", podId)
r, code, err := readBody(c.call("PUT", path, pms, nil))

if code == http.StatusNoContent || code == http.StatusOK {
return nil
} else if code == http.StatusNotFound {
return fmt.Errorf("pod %s not found", podId)
} else if err != nil {
return err
} else {
return fmt.Errorf("unexpect response code %d: %s", code, string(r))
}
}
46 changes: 18 additions & 28 deletions client/common_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"os"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/docker/docker/pkg/namesgenerator"
Expand Down Expand Up @@ -98,7 +97,7 @@ func (cli *HyperClient) JsonFromCmdline(container bool, cmdArgs, cmdEnvs, cmdPor
image = cmdArgs[0]
command = []string{}
env = []*apitype.EnvironmentVar{}
ports = []*apitype.UserContainerPort{}
ports = []*apitype.PortMapping{}
logOpts = make(map[string]string)
labels = make(map[string]string)
volumesRef = []*apitype.UserVolumeReference{}
Expand Down Expand Up @@ -170,7 +169,6 @@ func (cli *HyperClient) JsonFromCmdline(container bool, cmdArgs, cmdEnvs, cmdPor
Command: command,
Workdir: cmdWorkdir,
Entrypoint: entrypoints,
Ports: ports,
Envs: env,
Volumes: volumesRef,
Files: []*apitype.UserFileReference{},
Expand All @@ -190,6 +188,7 @@ func (cli *HyperClient) JsonFromCmdline(container bool, cmdArgs, cmdEnvs, cmdPor
Type: cmdLogDriver,
Config: logOpts,
},
Portmappings: ports,
}
body = userPod
}
Expand Down Expand Up @@ -265,45 +264,36 @@ func parseVolume(volStr string) (*apitype.UserVolume, *apitype.UserVolumeReferen
return &vol, &volRef, nil
}

func parsePortMapping(portmap string) (*apitype.UserContainerPort, error) {
func parsePortMapping(portmap string) (*apitype.PortMapping, error) {

var (
port = apitype.UserContainerPort{}
proto string
hPort string
cPort string
err error
tmp *apitype.PortMapping
port *apitype.PortMapping
err error
)

fields := strings.Split(portmap, ":")
if len(fields) < 2 {
return nil, fmt.Errorf("flag needs host port and container port: --publish")
} else if len(fields) == 2 {
proto = "tcp"
hPort = fields[0]
cPort = fields[1]
tmp = &apitype.PortMapping{
Protocol: "tcp",
ContainerPort: fields[1],
HostPort: fields[0],
}
} else {
proto = fields[0]
if proto != "tcp" && proto != "udp" {
return nil, fmt.Errorf("flag needs protocol(tcp or udp): --publish")
tmp = &apitype.PortMapping{
Protocol: fields[0],
ContainerPort: fields[2],
HostPort: fields[1],
}
hPort = fields[1]
cPort = fields[2]
}

port.Protocol = proto
hp, err := strconv.Atoi(hPort)
port.HostPort = int32(hp)
if err != nil {
return nil, fmt.Errorf("flag needs host port and container port: --publish: %v", err)
}
cp, err := strconv.Atoi(cPort)
port.ContainerPort = int32(cp)
port, err = tmp.Formalize()
if err != nil {
return nil, fmt.Errorf("flag needs host port and container port: --publish: %v", err)
return nil, err
}

return &port, nil
return port, nil
}

func imageToName(image string) string {
Expand Down
1 change: 1 addition & 0 deletions client/help_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Command:
login Register or log in to a Docker registry server
logout Log out from a Docker registry server
pause Pause a running pod
ports Show or modify port mapping rules
pull Pull an image from a Docker registry server
push Push an image or a repository to a Docker registry server
rm Remove one or more pods or containers
Expand Down
1 change: 1 addition & 0 deletions client/help_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Command:
login Register or log in to a Docker registry server
logout Log out from a Docker registry server
pause Pause a running pod
ports Show or modify port mapping rules
pull Pull an image from a Docker registry server
push Push an image or a repository to a Docker registry server
rm Remove one or more pods or containers
Expand Down
83 changes: 83 additions & 0 deletions client/portmapping.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package client

import (
"errors"
"fmt"
"strings"
"text/tabwriter"

"github.com/hyperhq/hyperd/types"
gflag "github.com/jessevdk/go-flags"
)

func (cli *HyperClient) HyperCmdPorts(args ...string) error {
var opts struct {
Portmap []string `short:"p" long:"publish" value-name:"[]" default-mask:"-" description:"Publish a container's port to the host, format: -p|--publish [tcp/udp:]hostPort:containerPort (only valid for add and delete)"`
}
var parser = gflag.NewParser(&opts, gflag.Default|gflag.IgnoreUnknown|gflag.PassAfterNonOption)
parser.Usage = "ports ls|add|delete [OPTIONS] POD\n\nList or modify port mapping rules of a Pod\n"

if len(args) == 0 {
parser.WriteHelp(cli.err)
return nil
}
cmd := args[0]

args, err := parser.ParseArgs(args[1:])
if err != nil {
if !strings.Contains(err.Error(), "Usage") {
return err
} else {
return nil
}
}

var modFunc func(string, []*types.PortMapping) error

switch cmd {
case "ls":
if len(args) != 1 {
return errors.New("need a Pod Id as command parameter")
}
pms, err := cli.client.ListPortMappings(args[0])
if err != nil {
return err
}
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
fmt.Fprintln(w, "Protocol\tHost Ports\tContainer Ports")
for _, pm := range pms {
fmt.Fprintf(w, "%s\t%s\t%s\n", pm.Protocol, pm.HostPort, pm.ContainerPort)
}
w.Flush()
return nil
case "add":
modFunc = cli.client.AddPortMappings
case "delete":
modFunc = cli.client.DeletePortMappings
default:
parser.WriteHelp(cli.err)
return nil
}

if len(args) != 1 {
return errors.New("need a Pod Id as command parameter")
}
if len(opts.Portmap) == 0 {
return errors.New("no rules to be add or delete")
}

pms := make([]*types.PortMapping, 0, len(opts.Portmap))
for _, o := range opts.Portmap {
pm, err := parsePortMapping(o)
if err != nil {
return fmt.Errorf("failed to parse rule %s: %v", o, err)
}
pms = append(pms, pm)
}

err = modFunc(args[0], pms)
if err != nil {
return err
}
return nil
}
12 changes: 11 additions & 1 deletion daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import (
"github.com/docker/docker/registry"
dockerutils "github.com/docker/docker/utils"
"github.com/golang/glog"
"github.com/hyperhq/hyperd/networking/portmapping"
"github.com/hyperhq/hyperd/utils"
"github.com/hyperhq/runv/driverloader"
"github.com/hyperhq/runv/factory"
"github.com/hyperhq/runv/hypervisor"
"github.com/hyperhq/runv/hypervisor/network"
)

var (
Expand Down Expand Up @@ -224,10 +226,18 @@ func (daemon *Daemon) initRunV(c *apitypes.HyperConfig) error {
}

func (daemon *Daemon) initNetworks(c *apitypes.HyperConfig) error {
if err := hypervisor.InitNetwork(c.Bridge, c.BridgeIP, c.DisableIptables); err != nil {
if err := hypervisor.InitNetwork(c.Bridge, c.BridgeIP, true); err != nil {
glog.Errorf("InitNetwork failed, %s", err.Error())
return err
}
addr, err := network.GetIfaceAddr(network.BridgeIface)
if err != nil {
glog.Errorf("failed to get address of the configured bridge: %v", err)
return err
}
if err := portmapping.Setup(network.BridgeIface, addr, c.DisableIptables); err != nil {
glog.Errorf("Setup portmapping failed: %v", err)
}
return nil
}

Expand Down
8 changes: 8 additions & 0 deletions daemon/pod/decommission.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,11 +549,13 @@ func (p *XPod) cleanup() {
if err != nil {
// even if error, we set the vm to be stopped
p.Log(ERROR, "pod stopping failed, failed to decommit the resources: %v", err)
err = nil
}

err = p.removeSandboxFromDB()
if err != nil {
p.Log(ERROR, "pod stopping failed, failed to remove sandbox persist data: %v", err)
err = nil
}

p.Log(DEBUG, "tag pod as stopped")
Expand All @@ -573,6 +575,12 @@ func (p *XPod) cleanup() {
func (p *XPod) decommissionResources() (err error) {
p.Log(DEBUG, "umount all containers and volumes, release IP addresses")

err = p.flushPortMapping()
if err != nil {
p.Log(WARNING, "(ignored) flush port mappings failed: %v", err)
err = nil
}

for _, c := range p.containers {
ec := c.umountRootVol()
if ec != nil {
Expand Down
Loading

0 comments on commit 20ab5d6

Please sign in to comment.