aboutsummaryrefslogtreecommitdiffstats
path: root/ansible/gen_scale_out_test.yml
blob: a76ea0ac2b18060c175e481f3716bd86767cf722 (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
# Copyright (c) 2017 Intel Corporation. #
# 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.
---
- hosts: localhost
  connection: local
  vars:
    vnf_range:
      - 2
      - 4
      - 10


  tasks:
    - include: scale_out_test_templates.yml
      with_items: "{{ vnf_range }}"
*/ .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/env python

"""
Generate the endpoint_map.yaml template from data in the endpoint_data.yaml
file.

By default the files in the same directory as this script are operated on, but
different files can be optionally specified on the command line.

The --check option verifies that the current output file is up-to-date with the
latest data in the input file. The script exits with status code 2 if a
mismatch is detected.
"""

from __future__ import print_function


__all__ = ['load_endpoint_data', 'generate_endpoint_map_template',
           'write_template', 'build_endpoint_map', 'check_up_to_date']


import collections
import copy
import itertools
import os
import sys
import yaml


(IN_FILE, OUT_FILE) = ('endpoint_data.yaml', 'endpoint_map.yaml')

SUBST = (SUBST_IP_ADDRESS, SUBST_CLOUDNAME) = ('IP_ADDRESS', 'CLOUDNAME')
PARAMS = (PARAM_CLOUD_ENDPOINTS, PARAM_ENDPOINTMAP, PARAM_NETIPMAP,
          PARAM_SERVICENETMAP) = (
          'CloudEndpoints', 'EndpointMap', 'NetIpMap', 'ServiceNetMap')
FIELDS = (F_PORT, F_PROTOCOL, F_HOST) = ('port', 'protocol', 'host')

ENDPOINT_TYPES = frozenset(['Internal', 'Public', 'Admin'])


def get_file(default_fn, override=None, writable=False):
    if override == '-':
        if writable:
            return sys.stdout
        else:
            return sys.stdin

    if override is not None:
        filename = override
    else:
        filename = os.path.join(os.path.dirname(__file__), default_fn)

    return open(filename, 'w' if writable else 'r')


def load_endpoint_data(infile=None):
    with get_file(IN_FILE, infile) as f:
        return yaml.safe_load(f)


def net_param_name(endpoint_type_defn):
    return endpoint_type_defn['net_param'] + 'Network'


def endpoint_map_default(config):
    def map_item(ep_name, ep_type, svc):
        values = collections.OrderedDict([
            (F_PROTOCOL, svc.get(F_PROTOCOL, 'http')),
            (F_PORT, str(svc[ep_type].get(F_PORT, svc[F_PORT]))),
            (F_HOST, SUBST_IP_ADDRESS),
        ])
        return ep_name + ep_type, values

    return collections.OrderedDict(map_item(ep_name, ep_type, svc)
                                   for ep_name, svc in sorted(config.items())
                                   for ep_type in sorted(set(svc) &
                                                         ENDPOINT_TYPES))


def make_parameter(ptype, default, description=None):
    param = collections.OrderedDict([('type', ptype), ('default', default)])
    if description is not None:
        param['description'] = description
    return param


def template_parameters(config):
    params = collections.OrderedDict()
    params[PARAM_NETIPMAP] = make_parameter('json', {}, 'The Net IP map')
    params[PARAM_SERVICENETMAP] = make_parameter('json', {}, 'The Service Net map')
    params[PARAM_ENDPOINTMAP] = make_parameter('json',
                                               endpoint_map_default(config),
                                               'Mapping of service endpoint '
                                               '-> protocol. Typically set '
                                               'via parameter_defaults in the '
                                               'resource registry.')

    params[PARAM_CLOUD_ENDPOINTS] = make_parameter(
        'json',
        {},
        ('A map containing the DNS names for the different endpoints '
         '(external, internal_api, etc.)'))
    return params


def template_output_definition(endpoint_name,
                               endpoint_variant,
                               endpoint_type,
                               net_param,
                               uri_suffix=None,
                               name_override=None):
    def extract_field(field):
        assert field in FIELDS
        return {'get_param': ['EndpointMap',
                              endpoint_name + endpoint_type,
                              copy.copy(field)]}

    port = extract_field(F_PORT)
    protocol = extract_field(F_PROTOCOL)
    host_nobrackets = {
        'str_replace': collections.OrderedDict([
            ('template', extract_field(F_HOST)),
            ('params', {
                SUBST_IP_ADDRESS: {'get_param':
                                   ['NetIpMap',
                                    {'get_param': ['ServiceNetMap',
                                     net_param]}]},
                SUBST_CLOUDNAME: {'get_param':
                                  [PARAM_CLOUD_ENDPOINTS,
                                   {'get_param': ['ServiceNetMap',
                                     net_param]}]},
            })
        ])
    }
    host = {
        'str_replace': collections.OrderedDict([
            ('template', extract_field(F_HOST)),
            ('params', {
                SUBST_IP_ADDRESS: {'get_param':
                                   ['NetIpMap',
                                    {'str_replace':
                                    {'template': 'NETWORK_uri',
                                     'params': {'NETWORK':
                                     {'get_param': ['ServiceNetMap',
                                                    net_param]}}}}]},
                SUBST_CLOUDNAME: {'get_param':
                                  [PARAM_CLOUD_ENDPOINTS,
                                   {'get_param': ['ServiceNetMap',
                                     net_param]}]},
            })
        ])
    }
    uri_fields = [protocol, '://', copy.deepcopy(host), ':', port]
    uri_fields_suffix = (copy.deepcopy(uri_fields) +
                         ([uri_suffix] if uri_suffix is not None else []))

    name = name_override if name_override is not None else (endpoint_name +
                                                            endpoint_variant +
                                                            endpoint_type)

    return name, {
        'host_nobrackets': host_nobrackets,
        'host': host,
        'port': extract_field('port'),
        'protocol': extract_field('protocol'),
        'uri': {
            'list_join': ['', uri_fields_suffix]
        },
        'uri_no_suffix': {
            'list_join': ['', uri_fields]
        },
    }


def template_endpoint_items(config):
    def get_svc_endpoints(ep_name, svc):
        for ep_type in set(svc) & ENDPOINT_TYPES:
            defn = svc[ep_type]
            for variant, suffix in defn.get('uri_suffixes',
                                            {'': None}).items():
                name_override = defn.get('names', {}).get(variant)
                yield template_output_definition(ep_name, variant, ep_type,
                                                 net_param_name(defn),
                                                 suffix,
                                                 name_override)
    return itertools.chain.from_iterable(sorted(get_svc_endpoints(ep_name,
                                                                  svc))
                                         for (ep_name,
                                              svc) in sorted(config.items()))


def generate_endpoint_map_template(config):
    return collections.OrderedDict([
        ('heat_template_version', '2015-04-30'),
        ('description', 'A map of OpenStack endpoints. Since the endpoints '
         'are URLs, we need to have brackets around IPv6 IP addresses. The '
         'inputs to these parameters come from net_ip_uri_map, which will '
         'include these brackets in IPv6 addresses.'),
        ('parameters', template_parameters(config)),
        ('outputs', {
            'endpoint_map': {
                'value':
                    collections.OrderedDict(template_endpoint_items(config))
            }
        }),
    ])


autogen_warning = """### DO NOT MODIFY THIS FILE
### This file is automatically generated from endpoint_data.yaml
### by the script build_endpoint_map.py

"""


class TemplateDumper(yaml.SafeDumper):
    def represent_ordered_dict(self, data):
        return self.represent_dict(data.items())


TemplateDumper.add_representer(collections.OrderedDict,
                               TemplateDumper.represent_ordered_dict)


def write_template(template, filename=None):
    with get_file(OUT_FILE, filename, writable=True) as f:
        f.write(autogen_warning)
        yaml.dump(template, f, TemplateDumper, width=68)


def read_template(template, filename=None):
    with get_file(OUT_FILE, filename) as f:
        return yaml.safe_load(f)


def build_endpoint_map(output_filename=None, input_filename=None):
    if output_filename is not None and output_filename == input_filename:
        raise Exception('Cannot read from and write to the same file')
    config = load_endpoint_data(input_filename)
    template = generate_endpoint_map_template(config)
    write_template(template, output_filename)


def check_up_to_date(output_filename=None, input_filename=None):
    if output_filename is not None and output_filename == input_filename:
        raise Exception('Input and output filenames must be different')
    config = load_endpoint_data(input_filename)
    template = generate_endpoint_map_template(config)
    existing_template = read_template(output_filename)
    return existing_template == template


def get_options():
    from optparse import OptionParser

    parser = OptionParser('usage: %prog'
                          ' [-i INPUT_FILE] [-o OUTPUT_FILE] [--check]',
                          description=__doc__)
    parser.add_option('-i', '--input', dest='input_file', action='store',
                      default=None,
                      help='Specify a different endpoint data file')
    parser.add_option('-o', '--output', dest='output_file', action='store',
                      default=None,
                      help='Specify a different endpoint map template file')
    parser.add_option('-c', '--check', dest='check', action='store_true',
                      default=False, help='Check that the output file is '
                                          'up to date with the data')
    parser.add_option('-d', '--debug', dest='debug', action='store_true',
                      default=False, help='Print stack traces on error')

    return parser.parse_args()


def main():
    options, args = get_options()
    if args:
        print('Warning: ignoring positional args: %s' % ' '.join(args),
              file=sys.stderr)

    try:
        if options.check:
            if not check_up_to_date(options.output_file, options.input_file):
                print('EndpointMap template does not match input data',
                      file=sys.stderr)
                sys.exit(2)
        else:
            build_endpoint_map(options.output_file, options.input_file)
    except Exception as exc:
        if options.debug:
            raise
        print('%s: %s' % (type(exc).__name__, str(exc)), file=sys.stderr)
        sys.exit(1)


if __name__ == '__main__':
    main()