asteris-llc/converge

View on GitHub
resource/docker/network/preparer.go

Summary

Maintainability
A
0 mins
Test Coverage
// Copyright © 2016 Asteris, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !solaris

package network

import (
    "github.com/asteris-llc/converge/load/registry"
    "github.com/asteris-llc/converge/resource"
    "github.com/asteris-llc/converge/resource/docker"
    dc "github.com/fsouza/go-dockerclient"
    "golang.org/x/net/context"
)

// Preparer for docker networks
//
// Network is responsible for managing Docker networks. It assumes that there is
// already a Docker daemon running on the system.
// *Note: docker resources are not currently supported on Solaris.*
type Preparer struct {
    // name of the network
    Name string `hcl:"name" required:"true" nonempty:"true"`

    // network driver. default: bridge
    Driver string `hcl:"driver"`

    // labels to set on the network
    Labels map[string]string `hcl:"labels"`

    // driver specific options
    Options map[string]interface{} `hcl:"options"`

    // ip address management driver. default: default
    IPAMDriver string `hcl:"ipam_driver"`

    // optional custom IPAM configuration. multiple IPAM configurations are
    // permitted. Each IPAM configuration block should contain one or more of the
    // following items:
    //
    //   * subnet:      subnet in CIDR format
    //   * gateway:     ipv4 or ipv6 gateway for the corresponding subnet
    //   * ip_range:    container ips are allocated from this sub-ranges (CIDR format)
    //   * aux_address: auxiliary ipv4 or ipv6 addresses used by the network driver.
    //                  Aux addresses are specified as a map with a name key and an IP
    //                  address value
    IPAMConfig []ipamConfigMap `hcl:"ipam_config"`

    // restricts external access to the network
    Internal bool `hcl:"internal"`

    // enable ipv6 networking
    IPv6 bool `hcl:"ipv6"`

    // indicates whether the network should exist. default: present
    State State `hcl:"state" valid_values:"present,absent"`

    // indicates whether or not the network will be recreated if the state is not
    // what is expected. By default, the module will only check to see if the
    // network exists. Specified as a boolean value
    Force bool `hcl:"force"`
}

// Prepare a docker network
func (p *Preparer) Prepare(ctx context.Context, render resource.Renderer) (resource.Task, error) {
    if p.Driver == "" {
        p.Driver = DefaultDriver
    }

    if p.IPAMDriver == "" {
        p.IPAMDriver = DefaultIPAMDriver
    }

    if p.State == "" {
        p.State = StatePresent
    }

    dockerClient, err := docker.NewDockerClient()
    if err != nil {
        return nil, err
    }

    nw := &Network{
        Name:     p.Name,
        Driver:   p.Driver,
        Labels:   p.Labels,
        Options:  p.Options,
        IPAM:     p.buildIPAMOptions(),
        Internal: p.Internal,
        IPv6:     p.IPv6,
        State:    p.State,
        Force:    p.Force,
    }
    nw.SetClient(dockerClient)
    return nw, nil
}

func (p *Preparer) buildIPAMOptions() dc.IPAMOptions {
    ipamOptions := dc.IPAMOptions{
        Driver: p.IPAMDriver,
    }

    for _, ipamConfigMap := range p.IPAMConfig {
        ipamConfig := ipamConfigMap.IPAMConfig()
        if ipamConfig.Subnet != "" || len(ipamConfig.AuxAddress) > 0 {
            ipamOptions.Config = append(ipamOptions.Config, ipamConfig)
        }
    }

    return ipamOptions
}

type ipamConfigMap map[string]interface{}

func (i ipamConfigMap) IPAMConfig() dc.IPAMConfig {
    config := dc.IPAMConfig{}
    subnet := i.value("subnet")
    if subnet != "" {
        config.Subnet = subnet
        config.Gateway = i.value("gateway")
        config.IPRange = i.value("ip_range")
    }

    if val, ok := i["aux_addresses"]; ok {
        if auxMap, ok := val.(map[string]interface{}); ok {
            auxAddrs := make(map[string]string)
            for name, ipval := range auxMap {
                if ip, ok := ipval.(string); ok {
                    auxAddrs[name] = ip
                }
            }
            config.AuxAddress = auxAddrs
        }
    }

    return config
}

func (i ipamConfigMap) value(key string) string {
    if val, ok := i[key]; ok {
        if strval, ok := val.(string); ok {
            return strval
        }
    }
    return ""
}

func init() {
    registry.Register("docker.network", (*Preparer)(nil), (*Network)(nil))
}