Skip to content

Commit

Permalink
feature: add update daemon config function
Browse files Browse the repository at this point in the history
Add update daemon config function. If pouchd is alive, it will change
daemon config if it supports, and then change the config file. If pouchd
is dead, it just update the daemon config file.

Pouchd dead:
You can specified the config file by set `--config-file` to update, more
functions you can see by `pouch updatedaemon --help`

Signed-off-by: Rudy Zhang <[email protected]>
  • Loading branch information
rudyfly committed Jun 19, 2018
1 parent 453b628 commit 7c773c1
Show file tree
Hide file tree
Showing 15 changed files with 329 additions and 66 deletions.
5 changes: 5 additions & 0 deletions apis/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1590,6 +1590,7 @@ definitions:
> are in compliance with any terms that cover redistributing
> nondistributable artifacts.
x-omitempty: true
type: "array"
items:
type: "string"
Expand All @@ -1616,6 +1617,7 @@ definitions:
> feature to push artifacts to private registries and ensure that you
> are in compliance with any terms that cover redistributing
> nondistributable artifacts.
x-omitempty: true
type: "array"
items:
type: "string"
Expand Down Expand Up @@ -1645,11 +1647,13 @@ definitions:
> should therefore ONLY be used for testing purposes. For increased
> security, users should add their CA to their system's list of trusted
> CAs instead of enabling this option.
x-omitempty: true
type: "array"
items:
type: "string"
example: ["::1/128", "127.0.0.0/8"]
IndexConfigs:
x-omitempty: true
type: "object"
additionalProperties:
$ref: "#/definitions/IndexInfo"
Expand All @@ -1671,6 +1675,7 @@ definitions:
Official: false
Mirrors:
description: "List of registry URLs that act as a mirror for the official registry."
x-omitempty: true
type: "array"
items:
type: "string"
Expand Down
8 changes: 4 additions & 4 deletions apis/types/registry_service_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func main() {
cli.AddCommand(base, &LogsCommand{})
cli.AddCommand(base, &RemountLxcfsCommand{})
cli.AddCommand(base, &WaitCommand{})
cli.AddCommand(base, &DaemonUpdateCommand{})

// add generate doc command
cli.AddCommand(base, &GenDocCommand{})
Expand Down
188 changes: 188 additions & 0 deletions cli/update_daemon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package main

import (
"bytes"
"context"
"encoding/json"
"io"
"io/ioutil"
"os"

"github.com/alibaba/pouch/apis/types"
"github.com/alibaba/pouch/daemon/config"

"github.com/pkg/errors"
"github.com/spf13/cobra"
)

// updateDescription is used to describe updatedaemon command in detail and auto generate command doc.
var daemonUpdateDescription = "Update daemon's configurations, if daemon is stoped, it will just update config file. " +
"Online update just including: image proxy, label, offline update including: manager white list, debug level, " +
"execute root directory, bridge name, bridge IP, fixed CIDR, defaut gateway, iptables, ipforwark, userland proxy" +
"If pouchd is alive, you can only use --offline=true to update config file"

// DaemonUpdateCommand use to implement 'updatedaemon' command, it modifies the configurations of a container.
type DaemonUpdateCommand struct {
baseCommand

configFile string
offline bool

debug bool
imageProxy string
label []string
managerWhiteList string
execRoot string
bridgeName string
bridgeIP string
fixedCIDR string
defaultGateway string
iptables bool
ipforward bool
userlandProxy bool
}

// Init initialize updatedaemon command.
func (udc *DaemonUpdateCommand) Init(c *Cli) {
udc.cli = c
udc.cmd = &cobra.Command{
Use: "updatedaemon [OPTIONS]",
Short: "Update the configurations of pouchd",
Long: daemonUpdateDescription,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return udc.daemonUpdateRun(args)
},
Example: daemonUpdateExample(),
}
udc.addFlags()
}

// addFlags adds flags for specific command.
func (udc *DaemonUpdateCommand) addFlags() {
flagSet := udc.cmd.Flags()
flagSet.SetInterspersed(false)
flagSet.StringVar(&udc.configFile, "config-file", "/etc/pouch/config.json", "specified config file for updating daemon")
flagSet.BoolVar(&udc.offline, "offline", false, "just update daemon config file")

flagSet.BoolVar(&udc.debug, "debug", false, "update daemon debug mode")
flagSet.StringVar(&udc.imageProxy, "image-proxy", "", "update daemon image proxy")
flagSet.StringVar(&udc.managerWhiteList, "manager-white-list", "", "update daemon manager white list")
flagSet.StringSliceVar(&udc.label, "label", nil, "update daemon labels")
flagSet.StringVar(&udc.execRoot, "exec-root-dir", "", "update exec root directory for network")
flagSet.StringVar(&udc.bridgeName, "bridge-name", "", "update daemon bridge device")
flagSet.StringVar(&udc.bridgeIP, "bip", "", "update daemon bridge IP")
flagSet.StringVar(&udc.fixedCIDR, "fixed-cidr", "", "update daemon bridge fixed CIDR")
flagSet.StringVar(&udc.defaultGateway, "default-gateway", "", "update daemon bridge default gateway")
flagSet.BoolVar(&udc.iptables, "iptables", true, "update daemon with iptables")
flagSet.BoolVar(&udc.ipforward, "ipforward", true, "udpate daemon with ipforward")
flagSet.BoolVar(&udc.userlandProxy, "userland-proxy", false, "update daemon with userland proxy")
}

// daemonUpdateRun is the entry of updatedaemon command.
func (udc *DaemonUpdateCommand) daemonUpdateRun(args []string) error {
ctx := context.Background()

apiClient := udc.cli.Client()

msg, err := apiClient.SystemPing(ctx)
if !udc.offline && err == nil && msg == "OK" {
// TODO: daemon support more configures for update online, such as debug level.
daemonConfig := &types.DaemonUpdateConfig{
ImageProxy: udc.imageProxy,
Labels: udc.label,
}

err = apiClient.DaemonUpdate(ctx, daemonConfig)
if err != nil {
return errors.Wrap(err, "failed to update alive daemon config")
}
} else {
// offline update config file.
err = udc.updateDaemonConfigFile()
if err != nil {
return errors.Wrap(err, "failed to update daemon config file.")
}
}

return nil
}

func (udc *DaemonUpdateCommand) updateDaemonConfigFile() error {
// read config from file.
contents, err := ioutil.ReadFile(udc.configFile)
if err != nil {
return errors.Wrapf(err, "failed to read config file(%s)", udc.configFile)
}

daemonConfig := &config.Config{}
if err = json.NewDecoder(bytes.NewReader(contents)).Decode(daemonConfig); err != nil {
return errors.Wrap(err, "failed to decode json: %s")
}

flagSet := udc.cmd.Flags()

if flagSet.Changed("image-proxy") {
daemonConfig.ImageProxy = udc.imageProxy
}

if flagSet.Changed("manager-white-list") {
daemonConfig.TLS.ManagerWhiteList = udc.managerWhiteList
}

// TODO: add parse labels

if flagSet.Changed("exec-root-dir") {
daemonConfig.NetworkConfig.ExecRoot = udc.execRoot
}

if flagSet.Changed("bridge-name") {
daemonConfig.NetworkConfig.BridgeConfig.Name = udc.bridgeName
}

if flagSet.Changed("bip") {
daemonConfig.NetworkConfig.BridgeConfig.IP = udc.bridgeIP
}

if flagSet.Changed("fixed-cidr") {
daemonConfig.NetworkConfig.BridgeConfig.FixedCIDR = udc.fixedCIDR
}

if flagSet.Changed("default-gateway") {
daemonConfig.NetworkConfig.BridgeConfig.GatewayIPv4 = udc.defaultGateway
}

if flagSet.Changed("iptables") {
daemonConfig.NetworkConfig.BridgeConfig.IPTables = udc.iptables
}

if flagSet.Changed("ipforward") {
daemonConfig.NetworkConfig.BridgeConfig.IPForward = udc.ipforward
}

if flagSet.Changed("userland-proxy") {
daemonConfig.NetworkConfig.BridgeConfig.UserlandProxy = udc.userlandProxy
}

// write config to file
fd, err := os.OpenFile(udc.configFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return errors.Wrapf(err, "failed to open config file(%s)", udc.configFile)
}
defer fd.Close()

fd.Seek(0, io.SeekStart)
encoder := json.NewEncoder(fd)
encoder.SetIndent("", " ")
err = encoder.Encode(daemonConfig)
if err != nil {
return errors.Wrapf(err, "failed to write config to file(%s)", udc.configFile)
}

return nil
}

// daemonUpdateExample shows examples in updatedaemon command, and is used in auto-generated cli docs.
func daemonUpdateExample() string {
return `$ pouch updatedaemon --debug=true`
}
4 changes: 2 additions & 2 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ type TLSConfig struct {
CA string `json:"tlscacert,omitempty"`
Cert string `json:"tlscert,omitempty"`
Key string `json:"tlskey,omitempty"`
VerifyRemote bool `json:"tlsverify"`
ManagerWhiteList string `json:"manager-whitelist"`
VerifyRemote bool `json:"tlsverify,omitempty"`
ManagerWhiteList string `json:"manager-whitelist,omitempty"`
}

// NewAPIClient initializes a new API client for the given host
Expand Down
18 changes: 18 additions & 0 deletions client/daemon_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package client

import (
"context"

"github.com/alibaba/pouch/apis/types"
)

// DaemonUpdate requests daemon to update daemon config.
func (client *APIClient) DaemonUpdate(ctx context.Context, config *types.DaemonUpdateConfig) error {
resp, err := client.post(ctx, "/daemon/update", nil, config, nil)
if err != nil {
return err
}

ensureCloseReader(resp)
return nil
}
51 changes: 51 additions & 0 deletions client/daemon_update_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package client

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"

"github.com/alibaba/pouch/apis/types"
)

func TestDaemonUpdateError(t *testing.T) {
client := &APIClient{
HTTPCli: newMockClient(errorMockResponse(http.StatusInternalServerError, "Server error")),
}
err := client.DaemonUpdate(context.Background(), &types.DaemonUpdateConfig{})
if err == nil || !strings.Contains(err.Error(), "Server error") {
t.Fatalf("expected a Server Error, got %v", err)
}
}

func TestDaemonUpdate(t *testing.T) {
expectedURL := "/daemon/update"

httpClient := newMockClient(func(req *http.Request) (*http.Response, error) {
if !strings.HasPrefix(req.URL.Path, expectedURL) {
return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedURL, req.URL)
}
if req.Header.Get("Content-Type") == "application/json" {
var updateConfig interface{}
if err := json.NewDecoder(req.Body).Decode(&updateConfig); err != nil {
return nil, fmt.Errorf("failed to parse json: %v", err)
}
}
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewReader([]byte(""))),
}, nil
})
client := &APIClient{
HTTPCli: httpClient,
}

if err := client.DaemonUpdate(context.Background(), &types.DaemonUpdateConfig{Labels: []string{"abc=def"}}); err != nil {
t.Fatal(err)
}
}
1 change: 1 addition & 0 deletions client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type SystemAPIClient interface {
SystemVersion(ctx context.Context) (*types.SystemVersion, error)
SystemInfo(ctx context.Context) (*types.SystemInfo, error)
RegistryLogin(ctx context.Context, auth *types.AuthConfig) (*types.AuthResponse, error)
DaemonUpdate(ctx context.Context, daemonConfig *types.DaemonUpdateConfig) error
}

// NetworkAPIClient defines methods of Network client.
Expand Down
10 changes: 5 additions & 5 deletions cri/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package config
// Config defines the CRI configuration.
type Config struct {
// Listen is the listening address which servers CRI.
Listen string
Listen string `json:"listen,omitempty"`
// NetworkPluginBinDir is the directory in which the binaries for the plugin is kept.
NetworkPluginBinDir string
NetworkPluginBinDir string `json:"network-plugin-bin-dir,omitempty"`
// NetworkPluginConfDir is the directory in which the admin places a CNI conf.
NetworkPluginConfDir string
NetworkPluginConfDir string `json:"network-plugin-conf-dir,omitempty"`
// SandboxImage is the image used by sandbox container.
SandboxImage string
SandboxImage string `json:"sandbox-image,omitempty"`
// CriVersion is the cri version
CriVersion string
CriVersion string `json:"cri-version,omitempty"`
}
Loading

0 comments on commit 7c773c1

Please sign in to comment.