コード例 #1
0
ファイル: docker.py プロジェクト: barryprice/charm-docker
def recycle_daemon():
    """
    Render the docker template files and restart the docker daemon on this
    system.

    :return: None
    """
    charm_config = check_for_juju_https_proxy(config)
    validate_config(charm_config)

    hookenv.log('Restarting docker service.')

    # Re-render our docker daemon template at this time... because we're
    # restarting. And its nice to play nice with others. Isn't that nice?
    opts = DockerOpts()
    runtime = determine_apt_source()
    render(
        'docker.defaults', '/etc/default/docker', {
            'opts': opts.to_s(),
            'manual': config('docker-opts'),
            'docker_runtime': runtime
        })
    render('docker.systemd', '/lib/systemd/system/docker.service',
           charm_config)

    reload_system_daemons()
    host.service_restart('docker')

    if not _probe_runtime_availability():
        status_set('waiting', 'Container runtime not available.')
        return
コード例 #2
0
ファイル: docker.py プロジェクト: mbruzek/layer-docker
def install():
    ''' Install the docker daemon, and supporting tooling '''
    # Often when building layer-docker based subordinates, you dont need to
    # incur the overhead of installing docker. This tuneable layer option
    # allows you to disable the exec of that install routine, and instead short
    # circuit immediately to docker.available, so you can charm away!
    layer_opts = layer.options('docker')
    if layer_opts['skip-install']:
        set_state('docker.available')
        set_state('docker.ready')
        return

    status_set('maintenance', 'Installing AUFS and other tools')
    kernel_release = check_output(['uname', '-r']).rstrip()
    packages = [
        'aufs-tools',
        'git',
        'linux-image-extra-{0}'.format(kernel_release),
    ]
    apt_update()
    apt_install(packages)
    # Install docker-engine from apt.
    install_from_apt()

    opts = DockerOpts()
    render('docker.defaults', '/etc/default/docker', {'opts': opts.to_s()})

    status_set('active', 'Docker installed, cycling for extensions')
    set_state('docker.ready')

    # Make with the adding of the users to the groups
    check_call(['usermod', '-aG', 'docker', 'ubuntu'])
コード例 #3
0
ファイル: docker.py プロジェクト: barryprice/charm-docker
def install():
    """
    Install the docker daemon, and supporting tooling.

    :return: None or False
    """
    # Switching runtimes causes a reinstall so remove any holds that exist.
    unhold_all()

    status_set('maintenance', 'Installing AUFS and other tools.')
    kernel_release = check_output(['uname', '-r']).rstrip()
    packages = [
        'aufs-tools',
        'git',
        'linux-image-extra-{}'.format(kernel_release.decode('utf-8')),
    ]
    apt_update()
    apt_install(packages)

    # Install docker-engine from apt.
    runtime = determine_apt_source()
    remove_state('nvidia-docker.supported')
    remove_state('nvidia-docker.installed')
    if runtime == 'upstream':
        install_from_upstream_apt()
    elif runtime == 'nvidia':
        set_state('nvidia-docker.supported')
        install_from_nvidia_apt()
        set_state('nvidia-docker.installed')
    elif runtime == 'apt':
        install_from_archive_apt()
    elif runtime == 'custom':
        if not install_from_custom_apt():
            return False  # If install fails, stop.
    else:
        hookenv.log('Unknown runtime {}'.format(runtime))
        return False

    charm_config = check_for_juju_https_proxy(config)
    validate_config(charm_config)

    opts = DockerOpts()
    render('docker.defaults', '/etc/default/docker', {
        'opts': opts.to_s(),
        'docker_runtime': runtime
    })
    render('docker.systemd', '/lib/systemd/system/docker.service',
           charm_config)
    reload_system_daemons()

    hold_all()
    hookenv.log(
        'Holding docker-engine and docker.io packages at current revision.')

    host.service_restart('docker')
    hookenv.log('Docker installed, setting "docker.ready" state.')
    set_state('docker.ready')

    # Make with the adding of the users to the groups
    check_call(['usermod', '-aG', 'docker', 'ubuntu'])
コード例 #4
0
ファイル: docker.py プロジェクト: juju-solutions/layer-docker
def scrub_sdn_config():
    ''' If this scenario of states is true, we have likely broken a
    relationship to our once configured SDN provider. This necessitates a
    cleanup of the Docker Options for BIP and MTU of the presumed dead SDN
    interface. '''

    opts = DockerOpts()
    try:
        opts.pop('bip')
    except KeyError:
        hookenv.log('Unable to locate bip in Docker config.')
        hookenv.log('Assuming no action required.')

    try:
        opts.pop('mtu')
    except KeyError:
        hookenv.log('Unable to locate mtu in Docker config.')
        hookenv.log('Assuming no action required.')

    # This method does everything we need to ensure the bridge configuration
    # has been removed. restarting the daemon restores docker with its default
    # networking mode.
    _remove_docker_network_bridge()
    recycle_daemon()
    remove_state('docker.sdn.configured')
コード例 #5
0
ファイル: flannel.py プロジェクト: chuckbutler/layer-flannel
def ingest_network_config():
    ''' When flannel configures itself on first boot, it generates an
    environment file (subnet.env).

    We will parse the data we need from this and cache in unitdata so we
    can hand it off between layers, and place in the dockeropts databag
    to configure the workload docker daemon
    '''
    db = unitdata.kv()
    opts = DockerOpts()

    if not os.path.isfile('subnet.env'):
        status_set('waiting', 'No subnet file to ingest.')
        return

    with open('subnet.env') as f:
        flannel_config = f.readlines()

    for f in flannel_config:
        if "FLANNEL_SUBNET" in f:
            value = f.split('=')[-1].strip()
            db.set('sdn_subnet', value)
            opts.add('bip', value)
        if "FLANNEL_MTU" in f:
            value = f.split('=')[1].strip()
            db.set('sdn_mtu', value)
            opts.add('mtu', value)

    set_state('sdn.available')
    set_state('flannel.configuring')
コード例 #6
0
def write_drop_ins():
    """
    Write the Docker systemd drop-ins.

    :return: None
    """
    opts = DockerOpts()
    runtime = determine_apt_source()
    charm_config = check_for_juju_https_proxy(config)

    validate_config(charm_config)

    render(
        "docker.defaults",
        "/etc/default/docker",
        {
            "opts": opts.to_s(),
            "extra_opts": config("docker-opts"),
            "docker_runtime": runtime,
        },
    )
    if not os.path.isdir("/etc/systemd/system/docker.service.d/"):
        host.mkdir("/etc/systemd/system/docker.service.d/")
    render(
        "docker-daemon.conf",
        "/etc/systemd/system/docker.service.d/docker-daemon.conf",
        {},
    )
    if charm_config.get("http_proxy") or charm_config.get("https_config"):
        render(
            "http-proxy.conf",
            "/etc/systemd/system/docker.service.d/http-proxy.conf",
            charm_config,
        )
コード例 #7
0
ファイル: docker.py プロジェクト: chr15p/layer-docker
def install():
    ''' Install the docker daemon, and supporting tooling '''

    # switching runtimes causes a reinstall so remove any holds that exist

    unholdall()

    # Often when building layer-docker based subordinates, you dont need to
    # incur the overhead of installing docker. This tuneable layer option
    # allows you to disable the exec of that install routine, and instead short
    # circuit immediately to docker.available, so you can charm away!
    layer_opts = layer.options('docker')
    if layer_opts['skip-install']:
        set_state('docker.available')
        set_state('docker.ready')
        return

    status_set('maintenance', 'Installing AUFS and other tools.')
    kernel_release = check_output(['uname', '-r']).rstrip()
    packages = [
        'aufs-tools',
        'git',
        'linux-image-extra-{0}'.format(kernel_release.decode('utf-8')),
    ]
    apt_update()
    apt_install(packages)

    # Install docker-engine from apt.
    runtime = determineAptSource()
    if runtime == "upstream":
        install_from_upstream_apt()
    elif runtime == "nvidia":
        install_from_nvidia_apt()
    elif runtime == "apt":
        install_from_archive_apt()
    else:
        hookenv.log('unknown runtime {0}'.format(runtime))
        return False

    validate_config()
    opts = DockerOpts()
    render('docker.defaults', '/etc/default/docker', {
        'opts': opts.to_s(),
        'docker_runtime': runtime
    })
    render('docker.systemd', '/lib/systemd/system/docker.service', config())
    reload_system_daemons()

    holdall()
    hookenv.log('Holding docker-engine and docker.io packages' +
                ' at current revision.')

    host.service_restart('docker')
    hookenv.log('Docker installed, setting "docker.ready" state.')
    set_state('docker.ready')

    # Make with the adding of the users to the groups
    check_call(['usermod', '-aG', 'docker', 'ubuntu'])
コード例 #8
0
def enable_client_tls():
    """
    Copy the TLS certificates in place and generate mount points for the swarm
    manager to mount the certs. This enables client-side TLS security on the
    TCP service.
    """
    if not path.exists('/etc/docker'):
        makedirs('/etc/docker')

    kv = unitdata.kv()
    cert = kv.get('tls.server.certificate')
    with open('/etc/docker/server.pem', 'w+') as f:
        f.write(cert)
    with open('/etc/docker/ca.pem', 'w+') as f:
        f.write(leader_get('certificate_authority'))

    # schenanigans
    keypath = 'easy-rsa/easyrsa3/pki/private/{}.key'
    server = getenv('JUJU_UNIT_NAME').replace('/', '_')
    if path.exists(keypath.format(server)):
        copyfile(keypath.format(server), '/etc/docker/server-key.pem')
    else:
        copyfile(keypath.format(unit_get('public-address')),
                 '/etc/docker/server-key.pem')

    opts = DockerOpts()
    config_dir = '/etc/docker'
    cert_path = '{}/server.pem'.format(config_dir)
    ca_path = '{}/ca.pem'.format(config_dir)
    key_path = '{}/server-key.pem'.format(config_dir)
    opts.add('tlscert', cert_path)
    opts.add('tlscacert', ca_path)
    opts.add('tlskey', key_path)
    opts.add('tlsverify', None)
    render('docker.defaults', '/etc/default/docker', {'opts': opts.to_s()})
コード例 #9
0
ファイル: docker.py プロジェクト: mbruzek/layer-docker
def recycle_daemon():
    ''' Other layers should be able to trigger a daemon restart '''
    status_set('maintenance', 'Restarting docker daemon')

    # Re-render our docker daemon template at this time... because we're
    # restarting. And its nice to play nice with others. Isn't that nice?
    opts = DockerOpts()
    render('docker.defaults', '/etc/default/docker', {'opts': opts.to_s()})

    service_restart('docker')
    remove_state('docker.restart')
コード例 #10
0
ファイル: swarm.py プロジェクト: juju-solutions/layer-swarm
def bind_docker_daemon(connection_string):
    """ Bind the docker daemon to a TCP socket with TLS credentials """
    status_set("maintenance", "Configuring Docker for TCP connections")
    opts = DockerOpts()
    private_address = unit_private_ip()
    opts.add("host", "tcp://{}:2376".format(private_address))
    opts.add("host", "unix:///var/run/docker.sock")
    opts.add("cluster-advertise", "{}:2376".format(private_address))
    opts.add("cluster-store", connection_string, strict=True)
    render("docker.defaults", "/etc/default/docker", {"opts": opts.to_s()})
    service_restart("docker")
    open_port(2376)
コード例 #11
0
ファイル: swarm.py プロジェクト: juju-solutions/layer-swarm
def enable_client_tls():
    """
    Copy the TLS certificates in place and generate mount points for the swarm
    manager to mount the certs. This enables client-side TLS security on the
    TCP service.
    """
    if not path.exists("/etc/docker"):
        makedirs("/etc/docker")

    kv = unitdata.kv()
    cert = kv.get("tls.server.certificate")
    with open("/etc/docker/server.pem", "w+") as f:
        f.write(cert)
    with open("/etc/docker/ca.pem", "w+") as f:
        f.write(leader_get("certificate_authority"))

    # schenanigans
    keypath = "easy-rsa/easyrsa3/pki/private/{}.key"
    server = getenv("JUJU_UNIT_NAME").replace("/", "_")
    if path.exists(keypath.format(server)):
        copyfile(keypath.format(server), "/etc/docker/server-key.pem")
    else:
        copyfile(keypath.format(unit_get("public-address")), "/etc/docker/server-key.pem")

    opts = DockerOpts()
    config_dir = "/etc/docker"
    cert_path = "{}/server.pem".format(config_dir)
    ca_path = "{}/ca.pem".format(config_dir)
    key_path = "{}/server-key.pem".format(config_dir)
    opts.add("tlscert", cert_path)
    opts.add("tlscacert", ca_path)
    opts.add("tlskey", key_path)
    opts.add("tlsverify", None)
    render("docker.defaults", "/etc/default/docker", {"opts": opts.to_s()})
コード例 #12
0
def render_configuration_template(service=False):
    """
    :param service: Boolean also render service file
    :return: None
    """
    opts = DockerOpts()
    config = hookenv.config

    environment_config = hookenv.env_proxy_settings()
    modified_config = dict(config())
    parsed_hosts = ""
    if environment_config is not None:
        hosts = []
        for address in environment_config.get('NO_PROXY', "").split(","):
            address = address.strip()
            try:
                net = ipaddress.ip_network(address)
                ip_addresses = [str(ip) for ip in net.hosts()]
                if ip_addresses == []:
                    hosts.append(address)
                else:
                    hosts += ip_addresses
            except ValueError:
                hosts.append(address)
        parsed_hosts = ",".join(hosts)
        environment_config.update({
            'NO_PROXY': parsed_hosts,
            'no_proxy': parsed_hosts
        })
        for key in ['http_proxy', 'https_proxy', 'no_proxy']:
            if not modified_config.get(key):
                modified_config[key] = environment_config.get(key)

    runtime = determine_apt_source()

    render(
        'docker.defaults', '/etc/default/docker', {
            'opts': opts.to_s(),
            'manual': config('docker-opts'),
            'docker_runtime': runtime
        })

    if service:
        render('docker.systemd', '/lib/systemd/system/docker.service',
               modified_config)

    write_daemon_json()
コード例 #13
0
ファイル: docker.py プロジェクト: juju-solutions/layer-docker
def recycle_daemon():
    '''Render the docker template files and restart the docker daemon on this
    system.'''
    hookenv.log('Restarting docker service.')

    # Re-render our docker daemon template at this time... because we're
    # restarting. And its nice to play nice with others. Isn't that nice?
    opts = DockerOpts()
    render('docker.defaults', '/etc/default/docker',
           {'opts': opts.to_s(), 'manual': config('docker-opts')})
    render('docker.systemd', '/lib/systemd/system/docker.service', config())
    reload_system_daemons()
    host.service_restart('docker')

    if not _probe_runtime_availability():
        status_set('waiting', 'Container runtime not available.')
        return
コード例 #14
0
ファイル: docker.py プロジェクト: barryprice/charm-docker
def manage_docker_opts(opts, remove=False):
    """
    Add or remove docker daemon options.

    Options here will be merged with configured docker-opts when layer-docker
    processes a daemon restart.

    :param opts: Dictionary keys/values; use None value if the key is a flag
    :param remove: Boolean True to remove the options; False to add them
    :return: None
    """
    try:
        docker_opts = DockerOpts()
    except Exception as e:
        hookenv.log(e)
        return

    for k, v in opts.items():
        # Always remove existing option
        if docker_opts.exists(k):
            docker_opts.pop(k)
        if not remove:
            docker_opts.add(k, v)
    hookenv.log('DockerOpts daemon options changed. Requesting a restart.')
    # State will be removed by layer-docker after restart
    set_state('docker.restart')
コード例 #15
0
ファイル: docker.py プロジェクト: yh742/kubernetes-deployment
def render_configuration_template(service=False):
    """
    :param service: Boolean also render service file
    :return: None
    """
    opts = DockerOpts()
    config = hookenv.config
    runtime = determine_apt_source()

    render(
        'docker.defaults', '/etc/default/docker', {
            'opts': opts.to_s(),
            'manual': config('docker-opts'),
            'docker_runtime': runtime
        })

    if service:
        render('docker.systemd', '/lib/systemd/system/docker.service',
               config())
コード例 #16
0
def recycle_daemon():
    '''Render the docker template files and restart the docker daemon on this
    system.'''
    hookenv.log('Restarting docker service.')

    # Re-render our docker daemon template at this time... because we're
    # restarting. And its nice to play nice with others. Isn't that nice?
    opts = DockerOpts()
    render('docker.defaults', '/etc/default/docker', {
        'opts': opts.to_s(),
        'manual': config('docker-opts')
    })
    render('docker.systemd', '/lib/systemd/system/docker.service', config())
    reload_system_daemons()
    host.service_restart('docker')

    if not _probe_runtime_availability():
        status_set('waiting', 'Container runtime not available.')
        return
コード例 #17
0
ファイル: docker.py プロジェクト: barryprice/charm-docker
def scrub_sdn_config():
    """
    If this scenario of states is true, we have likely broken a
    relationship to our once configured SDN provider. This necessitates a
    cleanup of the Docker Options for BIP and MTU of the presumed dead SDN
    interface.

    :return: None
    """
    opts = DockerOpts()
    try:
        opts.pop('bip')
    except KeyError:
        hookenv.log('Unable to locate bip in Docker config.')
        hookenv.log('Assuming no action required.')

    try:
        opts.pop('mtu')
    except KeyError:
        hookenv.log('Unable to locate mtu in Docker config.')
        hookenv.log('Assuming no action required.')

    # This method does everything we need to ensure the bridge configuration
    # has been removed. restarting the daemon restores docker with its default
    # networking mode.
    _remove_docker_network_bridge()
    recycle_daemon()
    remove_state('docker.sdn.configured')
コード例 #18
0
def install():
    ''' Install the docker daemon, and supporting tooling '''
    # Often when building layer-docker based subordinates, you dont need to
    # incur the overhead of installing docker. This tuneable layer option
    # allows you to disable the exec of that install routine, and instead short
    # circuit immediately to docker.available, so you can charm away!
    layer_opts = layer.options('docker')
    if layer_opts['skip-install']:
        set_state('docker.available')
        set_state('docker.ready')
        return

    status_set('maintenance', 'Installing AUFS and other tools.')
    kernel_release = check_output(['uname', '-r']).rstrip()
    packages = [
        'aufs-tools',
        'git',
        'linux-image-extra-{0}'.format(kernel_release.decode('utf-8')),
    ]
    apt_update()
    apt_install(packages)
    # Install docker-engine from apt.
    if config('install_from_upstream'):
        install_from_upstream_apt()
    else:
        install_from_archive_apt()

    opts = DockerOpts()
    render('docker.defaults', '/etc/default/docker', {'opts': opts.to_s()})
    render('docker.systemd', '/lib/systemd/system/docker.service', config())
    reload_system_daemons()

    hookenv.log('Docker installed, setting "docker.ready" state.')
    set_state('docker.ready')

    # Make with the adding of the users to the groups
    check_call(['usermod', '-aG', 'docker', 'ubuntu'])
コード例 #19
0
def swarm_etcd_cluster_setup(etcd):
    """
    Expose the Docker TCP port, and begin swarm cluster configuration. Always
    leading with the agent, connecting to the discovery service, then follow
    up with the manager container on the leader node.
    """
    opts = DockerOpts()
    # capture and place etcd TLS certificates
    certs = etcd.get_client_credentials()
    unit_name = getenv('JUJU_UNIT_NAME').replace('/', '-')
    cert_path = '/etc/ssl/{}'.format(unit_name)

    # if we have all the keys required, save them on disk
    if certs['client_ca'] and certs['client_key'] and certs['client_cert']:
        if not path.exists(cert_path):
            makedirs(cert_path)
        ca = "{}/client-ca.pem".format(cert_path)
        cert = "{}/client-cert.pem".format(cert_path)
        key = "{}/client-key.pem".format(cert_path)

        etcd.save_client_credentials(key, cert, ca)

    # format the connection string based on presence of encryption in the
    # connection string. Docker is the only known suite of tooling to use
    # the etcd:// protocol uri... dubious

    secure_discovery = 'https' in etcd.connection_string()
    if secure_discovery:
        con_string = etcd.connection_string().replace('https', 'etcd')
        ccert = 'kv.certfile={}'.format(cert)
        ckey = 'kv.keyfile={}'.format(key)
        cca = 'kv.cacertfile={}'.format(ca)
        opts.add('cluster-store-opt', ccert)
        opts.add('cluster-store-opt', ckey)
        opts.add('cluster-store-opt', cca)
    else:
        con_string = etcd.connection_string().replace('http', 'etcd')

    bind_docker_daemon(con_string)

    if secure_discovery:
        start_swarm(con_string, cert_path)
    else:
        start_swarm(con_string)

    status_set('active', 'Swarm configured. Happy swarming')
コード例 #20
0
ファイル: swarm.py プロジェクト: juju-solutions/layer-swarm
def swarm_etcd_cluster_setup(etcd):
    """
    Expose the Docker TCP port, and begin swarm cluster configuration. Always
    leading with the agent, connecting to the discovery service, then follow
    up with the manager container on the leader node.
    """
    opts = DockerOpts()
    # capture and place etcd TLS certificates
    certs = etcd.get_client_credentials()
    unit_name = getenv("JUJU_UNIT_NAME").replace("/", "-")
    cert_path = "/etc/ssl/{}".format(unit_name)

    # if we have all the keys required, save them on disk
    if certs["client_ca"] and certs["client_key"] and certs["client_cert"]:
        if not path.exists(cert_path):
            makedirs(cert_path)
        ca = "{}/client-ca.pem".format(cert_path)
        cert = "{}/client-cert.pem".format(cert_path)
        key = "{}/client-key.pem".format(cert_path)

        etcd.save_client_credentials(key, cert, ca)

    # format the connection string based on presence of encryption in the
    # connection string. Docker is the only known suite of tooling to use
    # the etcd:// protocol uri... dubious

    secure_discovery = "https" in etcd.connection_string()
    if secure_discovery:
        con_string = etcd.connection_string().replace("https", "etcd")
        ccert = "kv.certfile={}".format(cert)
        ckey = "kv.keyfile={}".format(key)
        cca = "kv.cacertfile={}".format(ca)
        opts.add("cluster-store-opt", ccert)
        opts.add("cluster-store-opt", ckey)
        opts.add("cluster-store-opt", cca)
    else:
        con_string = etcd.connection_string().replace("http", "etcd")

    bind_docker_daemon(con_string)

    if secure_discovery:
        start_swarm(con_string, cert_path)
    else:
        start_swarm(con_string)

    status_set("active", "Swarm configured. Happy swarming")
コード例 #21
0
def manage_docker_opts(opts, remove=False):
    '''Add or remove docker daemon options.

    Options here will be merged with configured docker-opts when layer-docker
    processes a daemon restart.

    :param: dict opts: option keys/values; use None value if the key is a flag
    :param: bool remove: True to remove the options; False to add them
    '''
    docker_opts = DockerOpts()
    for k, v in opts.items():
        # Always remove existing option
        if docker_opts.exists(k):
            docker_opts.pop(k)
        if not remove:
            docker_opts.add(k, v)
    hookenv.log('DockerOpts daemon options changed. Requesting a restart.')
    # State will be removed by layer-docker after restart
    set_state('docker.restart')
コード例 #22
0
ファイル: docker.py プロジェクト: juju-solutions/layer-docker
def container_sdn_setup(sdn):
    ''' Receive the information from the SDN plugin, and render the docker
    engine options. '''
    sdn_config = sdn.get_sdn_config()
    bind_ip = sdn_config['subnet']
    mtu = sdn_config['mtu']
    if data_changed('bip', bind_ip) or data_changed('mtu', mtu):
        status_set('maintenance', 'Configuring container runtime with SDN.')
        opts = DockerOpts()
        # This is a great way to misconfigure a docker daemon. Remove the
        # existing bind ip and mtu values of the SDN
        if opts.exists('bip'):
            opts.pop('bip')
        if opts.exists('mtu'):
            opts.pop('mtu')
        opts.add('bip', bind_ip)
        opts.add('mtu', mtu)
        _remove_docker_network_bridge()
        set_state('docker.sdn.configured')
コード例 #23
0
def bind_docker_daemon(connection_string):
    """ Bind the docker daemon to a TCP socket with TLS credentials """
    status_set('maintenance', 'Configuring Docker for TCP connections')
    opts = DockerOpts()
    private_address = unit_private_ip()
    opts.add('host', 'tcp://{}:2376'.format(private_address))
    opts.add('host', 'unix:///var/run/docker.sock')
    opts.add('cluster-advertise', '{}:2376'.format(private_address))
    opts.add('cluster-store', connection_string, strict=True)
    render('docker.defaults', '/etc/default/docker', {'opts': opts.to_s()})
    service_restart('docker')
    open_port(2376)
コード例 #24
0
ファイル: docker.py プロジェクト: barryprice/charm-docker
def container_sdn_setup(sdn):
    """
    Receive the information from the SDN plugin, and render the docker
    engine options.

    :param sdn: SDNPluginProvider
    :return: None
    """
    sdn_config = sdn.get_sdn_config()
    bind_ip = sdn_config['subnet']
    mtu = sdn_config['mtu']
    if data_changed('bip', bind_ip) or data_changed('mtu', mtu):
        status_set('maintenance', 'Configuring container runtime with SDN.')
        opts = DockerOpts()
        # This is a great way to misconfigure a docker daemon. Remove the
        # existing bind ip and mtu values of the SDN
        if opts.exists('bip'):
            opts.pop('bip')
        if opts.exists('mtu'):
            opts.pop('mtu')
        opts.add('bip', bind_ip)
        opts.add('mtu', mtu)
        _remove_docker_network_bridge()
        set_state('docker.sdn.configured')