summaryrefslogtreecommitdiffstats
path: root/mcp/patches/0012-routes-Skip-network-restart-on-noifupdown.patch
blob: fb42512ea30ba71afd55e9a2f6a49a2ea8ca86d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
: Copyright (c) 2018 Mirantis Inc., Enea AB and others.
:
: All rights reserved. This program and the accompanying materials
: are made available under the terms of the Apache License, Version 2.0
: which accompanies this distribution, and is available at
: http://www.apache.org/licenses/LICENSE-2.0
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
From: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
Date: Mon, 8 Jan 2018 05:09:11 +0100
Subject: [PATCH] routes: Skip network restart on 'noifupdown'

Previously, setting up routes did not allow passing 'require_reboot',
so each route change would lead to a networking service restart,
rendering interface configuration options like 'noifupdown' useless.
Allow disabling network restart per-interface using the existing
'noifupdown' option.

Signed-off-by: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
---
 linux/network/interface.sls | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/linux/network/interface.sls b/linux/network/interface.sls
index 921ceac..6ebc670 100644
--- a/linux/network/interface.sls
+++ b/linux/network/interface.sls
@@ -338,6 +338,9 @@ linux_network_{{ interface_name }}_routes:
       gateway: {{ route.gateway }}
       {%- endif %}
     {%- endfor %}
+  {%- if interface.noifupdown is defined %}
+  - require_reboot: {{ interface.noifupdown }}
+  {%- endif %}

 {%- endif %}
color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
#!/usr/bin/python
###############################################################################
# Copyright (c) 2015 Ericsson AB and others.
# szilard.cserey@ericsson.com
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
###############################################################################


import time
import os
import yaml
import glob
import shutil
import tempfile

from common import (
    N,
    E,
    R,
    ArgParser,
    exec_cmd,
    parse,
    err,
    log,
    delete,
    commafy,
)

DEA_1 = '''
title: Deployment Environment Adapter (DEA)
# DEA API version supported
version: 1.1
created: {date}
comment: {comment}
'''

DHA_1 = '''
title: Deployment Hardware Adapter (DHA)
# DHA API version supported
version: 1.1
created: {date}
comment: {comment}

# Adapter to use for this definition
# adapter: [ipmi|libvirt]
adapter:

# Node list.
# Mandatory properties are id and role.
# All other properties are adapter specific.
# For Non-Fuel nodes controlled by:
#   - ipmi adapter you need to provide:
#       pxeMac
#       ipmiIp
#       ipmiUser
#       ipmiPass
#   - libvirt adapter you need to provide:
#       libvirtName: <whatever>
#       libvirtTemplate: [libvirt/vms/controller.xml | libvirt/vms/compute.xml]
#
# For the Fuel Node you need to provide:
#       libvirtName: <whatever>
#       libvirtTemplate: libvirt/vms/fuel.xml
#       isFuel: yes
#       username: root
#       password: r00tme
'''

DHA_2 = '''
# Adding the Fuel node as node id {node_id}
# which may not be correct - please adjust as needed.
'''

DISKS = {'fuel': '100G',
         'controller': '100G',
         'compute': '100G'}


class Reap(object):

    def __init__(self, dea_file, dha_file, comment):
        self.dea_file = dea_file
        self.dha_file = dha_file
        self.comment = comment
        self.temp_dir = None
        self.env = None
        self.env_id = None
        self.last_node = None

    def get_env(self):
        env_list = parse(exec_cmd('fuel env'))
        if len(env_list) > 1:
            err('Not exactly one environment')
        self.env = env_list[0]
        self.env_id = self.env[E['id']]

    def download_config(self, config_type):
        log('Download %s config for environment %s'
            % (config_type, self.env_id))
        exec_cmd('fuel %s --env %s --download --dir %s'
                 % (config_type, self.env_id, self.temp_dir))

    def download_node_config(self, nodeid):
        log('Download node %s config for environment %s to %s'
            % (nodeid, self.env_id,self.temp_dir))
        exec_cmd('fuel deployment --node-id %s --env %s  --default --dir %s'
                 % (nodeid, self.env_id, self.temp_dir))

    def write(self, file, text, newline=True):
        mode = 'a' if os.path.isfile(file) else 'w'
        with open(file, mode) as f:
            f.write('%s%s' % (text, ('\n' if newline else '')))

    def write_yaml(self, file, data, newline=True):
        self.write(file, yaml.dump(data, default_flow_style=False).strip(),
                   newline)

    def get_node_by_id(self, node_list, node_id):
        for node in node_list:
            if node[N['id']] == node_id:
                return node

    def reap_interface(self, node_id, interfaces):
        interface, mac = self.get_interface(node_id)
        if_name = None
        if interfaces:
            if_name = self.check_dict_exists(interfaces, interface)
        if not if_name:
            if_name = 'interfaces_%s' % str(len(interfaces) + 1)
            interfaces[if_name] = interface
        return if_name, mac

    def reap_transformation(self, node_id, roles, transformations):
        main_role = 'controller' if 'controller' in roles else 'compute'
        node_file = glob.glob('%s/deployment_%s/*%s_%s.yaml'
                              % (self.temp_dir, self.env_id,
                                 main_role, node_id))
        tr_name = None
        with open(node_file[0]) as f:
            node_config = yaml.load(f)
        transformation = {'transformations':
                              node_config['network_scheme']['transformations']}
        if transformations:
            tr_name = self.check_dict_exists(transformations, transformation)
        if not tr_name:
            tr_name = 'transformations_%s' % str(len(transformations) + 1)
            transformations[tr_name] = transformation
        return tr_name

    def check_dict_exists(self, main_dict, dict):
        for key, val in main_dict.iteritems():
            if cmp(dict, val) == 0:
                return key

    def reap_nodes_interfaces_transformations(self):
        node_list = parse(exec_cmd('fuel node'))
        real_node_ids = [node[N['id']] for node in node_list]
        real_node_ids.sort()
        min_node = real_node_ids[0]
        interfaces = {}
        transformations = {}
        dea_nodes = []
        dha_nodes = []

        for real_node_id in real_node_ids:
            node_id = int(real_node_id) - int(min_node) + 1
            self.last_node = node_id
            node = self.get_node_by_id(node_list, real_node_id)
            roles = commafy(node[N['roles']])
            if not roles:
                err('Fuel Node %s has no role' % real_node_id)
            dea_node = {'id': node_id,
                        'role': roles}
            dha_node = {'id': node_id}
            if_name, mac = self.reap_interface(real_node_id, interfaces)
            log('reap transformation for node %s' % real_node_id)
            tr_name = self.reap_transformation(real_node_id, roles,
                                               transformations)
            dea_node.update(
                {'interfaces': if_name,
                 'transformations': tr_name})

            dha_node.update(
                {'pxeMac': mac if mac else None,
                 'ipmiIp': None,
                 'ipmiUser': None,
                 'ipmiPass': None,
                 'libvirtName': None,
                 'libvirtTemplate': None})

            dea_nodes.append(dea_node)
            dha_nodes.append(dha_node)

        self.write_yaml(self.dha_file, {'nodes': dha_nodes}, False)
        self.write_yaml(self.dea_file, {'nodes': dea_nodes})
        self.write_yaml(self.dea_file, interfaces)
        self.write_yaml(self.dea_file, transformations)
        self.reap_fuel_node_info()
        self.write_yaml(self.dha_file, {'disks': DISKS})

    def reap_fuel_node_info(self):
        dha_nodes = []
        dha_node = {
            'id': self.last_node + 1,
            'libvirtName': None,
            'libvirtTemplate': None,
            'isFuel': True,
            'username': 'root',
            'password': 'r00tme'}

        dha_nodes.append(dha_node)

        self.write(self.dha_file, DHA_2.format(node_id=dha_node['id']), False)
        self.write_yaml(self.dha_file, dha_nodes)

    def reap_environment_info(self):
        network_file = ('%s/network_%s.yaml'
                        % (self.temp_dir, self.env_id))
        network = self.read_yaml(network_file)

        env = {'environment':
                   {'name': self.env[E['name']],
                    'net_segment_type':
                        network['networking_parameters']['segmentation_type']}}
        self.write_yaml(self.dea_file, env)
        wanted_release = None
        rel_list = parse(exec_cmd('fuel release'))
        for rel in rel_list:
            if rel[R['id']] == self.env[E['release_id']]:
                wanted_release = rel[R['name']]
        self.write_yaml(self.dea_file, {'wanted_release': wanted_release})

    def reap_fuel_settings(self):
        data = self.read_yaml('/etc/fuel/astute.yaml')
        fuel = {}
        del data['ADMIN_NETWORK']['mac']
        del data['ADMIN_NETWORK']['interface']
        for key in ['ADMIN_NETWORK', 'HOSTNAME', 'DNS_DOMAIN', 'DNS_SEARCH',
                    'DNS_UPSTREAM', 'NTP1', 'NTP2', 'NTP3', 'FUEL_ACCESS']:
            fuel[key] = data[key]
        for key in fuel['ADMIN_NETWORK'].keys():
            if key not in ['ipaddress', 'netmask',
                           'dhcp_pool_start', 'dhcp_pool_end']:
                del fuel['ADMIN_NETWORK'][key]
        self.write_yaml(self.dea_file, {'fuel': fuel})

    def reap_network_settings(self):
        network_file = ('%s/network_%s.yaml'
                        % (self.temp_dir, self.env_id))
        data = self.read_yaml(network_file)
        network = {}
        network['networking_parameters'] = data['networking_parameters']
        network['networks'] = data['networks']
        for net in network['networks']:
            del net['id']
            del net['group_id']
        self.write_yaml(self.dea_file, {'network': network})

    def reap_settings(self):
        settings_file = '%s/settings_%s.yaml' % (self.temp_dir, self.env_id)
        settings = self.read_yaml(settings_file)
        self.write_yaml(self.dea_file, {'settings': settings})

    def get_interface(self, real_node_id):
        exec_cmd('fuel node --node-id %s --network --download --dir %s'
                 % (real_node_id, self.temp_dir))
        interface_file = ('%s/node_%s/interfaces.yaml'
                          % (self.temp_dir, real_node_id))
        interfaces = self.read_yaml(interface_file)
        interface_config = {}
        pxe_mac = None
        for interface in interfaces:
            networks = []
            for network in interface['assigned_networks']:
                networks.append(network['name'])
                if network['name'] == 'fuelweb_admin':
                    pxe_mac = interface['mac']
            if networks:
                interface_config[interface['name']] = networks
        return interface_config, pxe_mac

    def read_yaml(self, yaml_file):
        with open(yaml_file) as f:
            data = yaml.load(f)
            return data

    def intro(self):
        delete(self.dea_file)
        delete(self.dha_file)
        self.temp_dir = tempfile.mkdtemp()
        date = time.strftime('%c')
        self.write(self.dea_file,
                   DEA_1.format(date=date, comment=self.comment), False)
        self.write(self.dha_file,
                   DHA_1.format(date=date, comment=self.comment))
        self.get_env()

        # Need to download deployment with explicit node ids
        node_list = parse(exec_cmd('fuel node'))
        real_node_ids = [node[N['id']] for node in node_list]
        real_node_ids.sort()
        self.download_node_config(','.join(real_node_ids))

        self.download_config('settings')
        self.download_config('network')

    def finale(self):
        log('DEA file is available at %s' % self.dea_file)
        log('DHA file is available at %s (this is just a template)'
            % self.dha_file)
        shutil.rmtree(self.temp_dir)

    def reap(self):
        self.intro()
        self.reap_environment_info()
        self.reap_nodes_interfaces_transformations()
        self.reap_fuel_settings()
        self.reap_network_settings()
        self.reap_settings()
        self.finale()


def usage():
    print '''
    Usage:
    python reap.py <dea_file> <dha_file> <comment>
    '''


def parse_arguments():
    parser = ArgParser(prog='python %s' % __file__)
    parser.add_argument('dea_file', nargs='?', action='store',
                        default='dea.yaml',
                        help='Deployment Environment Adapter: dea.yaml')
    parser.add_argument('dha_file', nargs='?', action='store',
                        default='dha.yaml',
                        help='Deployment Hardware Adapter: dha.yaml')
    parser.add_argument('comment', nargs='?', action='store', help='Comment')
    args = parser.parse_args()
    return (args.dea_file, args.dha_file, args.comment)


def main():
    dea_file, dha_file, comment = parse_arguments()

    r = Reap(dea_file, dha_file, comment)
    r.reap()


if __name__ == '__main__':
    main()