Add http(s)_proxy handling to apex
[apex.git] / apex / deploy.py
index ceef160..fe25634 100644 (file)
@@ -13,27 +13,32 @@ import argparse
 import json
 import logging
 import os
+import platform
 import pprint
 import shutil
 import sys
 import tempfile
 
 import apex.virtual.configure_vm as vm_lib
-import apex.virtual.virtual_utils as virt_utils
+import apex.virtual.utils as virt_utils
 from apex import DeploySettings
 from apex import Inventory
 from apex import NetworkEnvironment
 from apex import NetworkSettings
+from apex.builders import common_builder as c_builder
+from apex.builders import overcloud_builder as oc_builder
+from apex.builders import undercloud_builder as uc_builder
 from apex.common import utils
 from apex.common import constants
 from apex.common import parsers
 from apex.common.exceptions import ApexDeployException
 from apex.network import jumphost
+from apex.network import network_data
 from apex.undercloud import undercloud as uc_lib
 from apex.overcloud import config as oc_cfg
-from apex.overcloud import overcloud_deploy
+from apex.overcloud import deploy as oc_deploy
 
-APEX_TEMP_DIR = tempfile.mkdtemp()
+APEX_TEMP_DIR = tempfile.mkdtemp(prefix='apex_tmp')
 ANSIBLE_PATH = 'ansible/playbooks'
 SDN_IMAGE = 'overcloud-full-opendaylight.qcow2'
 
@@ -57,6 +62,14 @@ def validate_cross_settings(deploy_settings, net_settings, inventory):
         raise ApexDeployException("Setting a DPDK based dataplane requires"
                                   "a dedicated NIC for tenant network")
 
+    if 'odl_vpp_routing_node' in deploy_settings['deploy_options']:
+        if deploy_settings['deploy_options']['dataplane'] != 'fdio':
+            raise ApexDeployException("odl_vpp_routing_node should only be set"
+                                      "when dataplane is set to fdio")
+        if deploy_settings['deploy_options'].get('dvr') is True:
+            raise ApexDeployException("odl_vpp_routing_node should only be set"
+                                      "when dvr is not enabled")
+
     # TODO(trozet): add more checks here like RAM for ODL, etc
     # check if odl_vpp_netvirt is true and vpp is set
     # Check if fdio and nosdn:
@@ -64,7 +77,8 @@ def validate_cross_settings(deploy_settings, net_settings, inventory):
     # "$tenant_nic_mapping_compute_members
 
 
-def build_vms(inventory, network_settings):
+def build_vms(inventory, network_settings,
+              template_dir='/usr/share/opnfv-apex'):
     """
     Creates VMs and configures vbmc and host
     :param inventory:
@@ -76,13 +90,13 @@ def build_vms(inventory, network_settings):
         name = 'baremetal{}'.format(idx)
         volume = name + ".qcow2"
         volume_path = os.path.join(constants.LIBVIRT_VOLUME_PATH, volume)
-        # TODO(trozet): add back aarch64
         # TODO(trozet): add error checking
         vm_lib.create_vm(
             name, volume_path,
             baremetal_interfaces=network_settings.enabled_network_list,
             memory=node['memory'], cpus=node['cpu'],
-            macs=[node['mac_address']])
+            macs=node['mac'],
+            template_dir=template_dir)
         virt_utils.host_setup({name: node['pm_port']})
 
 
@@ -110,7 +124,8 @@ def create_deploy_parser():
     deploy_parser.add_argument('-e', '--environment-file',
                                dest='env_file',
                                default='opnfv-environment.yaml',
-                               help='Provide alternate base env file')
+                               help='Provide alternate base env file located '
+                                    'in deploy_dir')
     deploy_parser.add_argument('-v', '--virtual', action='store_true',
                                default=False,
                                dest='virtual',
@@ -123,22 +138,26 @@ def create_deploy_parser():
     deploy_parser.add_argument('--virtual-computes',
                                dest='virt_compute_nodes',
                                default=1,
+                               type=int,
                                help='Number of Virtual Compute nodes to create'
                                     ' and use during deployment (defaults to 1'
                                     ' for noha and 2 for ha)')
     deploy_parser.add_argument('--virtual-cpus',
                                dest='virt_cpus',
                                default=4,
+                               type=int,
                                help='Number of CPUs to use per Overcloud VM in'
                                     ' a virtual deployment (defaults to 4)')
     deploy_parser.add_argument('--virtual-default-ram',
                                dest='virt_default_ram',
                                default=8,
+                               type=int,
                                help='Amount of default RAM to use per '
                                     'Overcloud VM in GB (defaults to 8).')
     deploy_parser.add_argument('--virtual-compute-ram',
                                dest='virt_compute_ram',
                                default=None,
+                               type=int,
                                help='Amount of RAM to use per Overcloud '
                                     'Compute VM in GB (defaults to 8). '
                                     'Overrides --virtual-default-ram arg for '
@@ -158,6 +177,10 @@ def create_deploy_parser():
     deploy_parser.add_argument('--quickstart', action='store_true',
                                default=False,
                                help='Use tripleo-quickstart to deploy')
+    deploy_parser.add_argument('--upstream', action='store_true',
+                               default=False,
+                               help='Force deployment to use upstream '
+                                    'artifacts')
     return deploy_parser
 
 
@@ -211,6 +234,7 @@ def main():
     console.setLevel(log_level)
     console.setFormatter(logging.Formatter(formatter))
     logging.getLogger('').addHandler(console)
+    utils.install_ansible()
     validate_deploy_args(args)
     # Parse all settings
     deploy_settings = DeploySettings(args.deploy_settings_file)
@@ -219,11 +243,17 @@ def main():
     net_settings = NetworkSettings(args.network_settings_file)
     logging.info("Network settings are:\n {}".format(pprint.pformat(
                  net_settings)))
+    os_version = deploy_settings['deploy_options']['os_version']
     net_env_file = os.path.join(args.deploy_dir, constants.NET_ENV_FILE)
-    net_env = NetworkEnvironment(net_settings, net_env_file)
+    net_env = NetworkEnvironment(net_settings, net_env_file,
+                                 os_version=os_version)
     net_env_target = os.path.join(APEX_TEMP_DIR, constants.NET_ENV_FILE)
     utils.dump_yaml(dict(net_env), net_env_target)
+
+    # get global deploy params
     ha_enabled = deploy_settings['global_params']['ha_enabled']
+    introspect = deploy_settings['global_params'].get('introspect', True)
+
     if args.virtual:
         if args.virt_compute_ram is None:
             compute_ram = args.virt_default_ram
@@ -254,7 +284,7 @@ def main():
     inventory = Inventory(args.inventory_file, ha_enabled, args.virtual)
 
     validate_cross_settings(deploy_settings, net_settings, inventory)
-
+    ds_opts = deploy_settings['deploy_options']
     if args.quickstart:
         deploy_settings_file = os.path.join(APEX_TEMP_DIR,
                                             'apex_deploy_settings.yaml')
@@ -274,28 +304,30 @@ def main():
         ansible_args = {
             'virsh_enabled_networks': net_settings.enabled_network_list
         }
-        ansible_path = os.path.join(args.lib_dir, ANSIBLE_PATH)
         utils.run_ansible(ansible_args,
-                          os.path.join(args.lib_dir,
-                                       ansible_path,
+                          os.path.join(args.lib_dir, ANSIBLE_PATH,
                                        'deploy_dependencies.yml'))
         uc_external = False
         if 'external' in net_settings.enabled_network_list:
             uc_external = True
         if args.virtual:
             # create all overcloud VMs
-            build_vms(inventory, net_settings)
+            build_vms(inventory, net_settings, args.deploy_dir)
         else:
             # Attach interfaces to jumphost for baremetal deployment
             jump_networks = ['admin']
             if uc_external:
                 jump_networks.append('external')
             for network in jump_networks:
-                iface = net_settings['networks'][network]['installer_vm'][
-                    'members'][0]
+                if network == 'external':
+                    # TODO(trozet): enable vlan secondary external networks
+                    iface = net_settings['networks'][network][0][
+                        'installer_vm']['members'][0]
+                else:
+                    iface = net_settings['networks'][network]['installer_vm'][
+                        'members'][0]
                 bridge = "br-{}".format(network)
                 jumphost.attach_interface_to_ovs(bridge, iface, network)
-        # Dump all settings out to temp bash files to be sourced
         instackenv_json = os.path.join(APEX_TEMP_DIR, 'instackenv.json')
         with open(instackenv_json, 'w') as fh:
             json.dump(inventory, fh)
@@ -305,9 +337,52 @@ def main():
             root_pw = constants.DEBUG_OVERCLOUD_PW
         else:
             root_pw = None
+
+        upstream = (os_version != constants.DEFAULT_OS_VERSION or
+                    args.upstream)
+        if os_version == 'master':
+            branch = 'master'
+        else:
+            branch = "stable/{}".format(os_version)
+        if upstream:
+            logging.info("Deploying with upstream artifacts for OpenStack "
+                         "{}".format(os_version))
+            args.image_dir = os.path.join(args.image_dir, os_version)
+            upstream_url = constants.UPSTREAM_RDO.replace(
+                constants.DEFAULT_OS_VERSION, os_version)
+            upstream_targets = ['overcloud-full.tar', 'undercloud.qcow2']
+            utils.fetch_upstream_and_unpack(args.image_dir, upstream_url,
+                                            upstream_targets)
+            sdn_image = os.path.join(args.image_dir, 'overcloud-full.qcow2')
+            if ds_opts['sdn_controller'] == 'opendaylight':
+                logging.info("Preparing upstream image with OpenDaylight")
+                oc_builder.inject_opendaylight(
+                    odl_version=ds_opts['odl_version'],
+                    image=sdn_image,
+                    tmp_dir=APEX_TEMP_DIR
+                )
+            # copy undercloud so we don't taint upstream fetch
+            uc_image = os.path.join(args.image_dir, 'undercloud_mod.qcow2')
+            uc_fetch_img = os.path.join(args.image_dir, 'undercloud.qcow2')
+            shutil.copyfile(uc_fetch_img, uc_image)
+            # prep undercloud with required packages
+            uc_builder.add_upstream_packages(uc_image)
+            # add patches from upstream to undercloud and overcloud
+            logging.info('Adding patches to undercloud')
+            patches = deploy_settings['global_params']['patches']
+            c_builder.add_upstream_patches(patches['undercloud'], uc_image,
+                                           APEX_TEMP_DIR, branch)
+            logging.info('Adding patches to overcloud')
+            c_builder.add_upstream_patches(patches['overcloud'], sdn_image,
+                                           APEX_TEMP_DIR, branch)
+        else:
+            sdn_image = os.path.join(args.image_dir, SDN_IMAGE)
+            uc_image = 'undercloud.qcow2'
         undercloud = uc_lib.Undercloud(args.image_dir,
+                                       args.deploy_dir,
                                        root_pw=root_pw,
-                                       external_network=uc_external)
+                                       external_network=uc_external,
+                                       image_name=os.path.basename(uc_image))
         undercloud.start()
 
         # Generate nic templates
@@ -315,24 +390,42 @@ def main():
             oc_cfg.create_nic_template(net_settings, deploy_settings, role,
                                        args.deploy_dir, APEX_TEMP_DIR)
         # Install Undercloud
-        undercloud.configure(net_settings,
-                             os.path.join(args.lib_dir,
-                                          ansible_path,
+        undercloud.configure(net_settings, deploy_settings,
+                             os.path.join(args.lib_dir, ANSIBLE_PATH,
                                           'configure_undercloud.yml'),
                              APEX_TEMP_DIR)
 
         # Prepare overcloud-full.qcow2
         logging.info("Preparing Overcloud for deployment...")
-        sdn_image = os.path.join(args.image_dir, SDN_IMAGE)
-        overcloud_deploy.prep_image(deploy_settings, sdn_image, APEX_TEMP_DIR,
-                                    root_pw=root_pw)
+        if os_version != 'ocata':
+            net_data_file = os.path.join(APEX_TEMP_DIR, 'network_data.yaml')
+            net_data = network_data.create_network_data(net_settings,
+                                                        net_data_file)
+        else:
+            net_data = False
+        if upstream and args.env_file == 'opnfv-environment.yaml':
+            # Override the env_file if it is defaulted to opnfv
+            # opnfv env file will not work with upstream
+            args.env_file = 'upstream-environment.yaml'
         opnfv_env = os.path.join(args.deploy_dir, args.env_file)
-        overcloud_deploy.prep_env(deploy_settings, net_settings, opnfv_env,
-                                  net_env_target, APEX_TEMP_DIR)
-        overcloud_deploy.create_deploy_cmd(deploy_settings, net_settings,
-                                           inventory, APEX_TEMP_DIR,
-                                           args.virtual, args.env_file)
-        deploy_playbook = os.path.join(args.lib_dir, ansible_path,
+        if not upstream:
+            oc_deploy.prep_env(deploy_settings, net_settings, inventory,
+                               opnfv_env, net_env_target, APEX_TEMP_DIR)
+            oc_deploy.prep_image(deploy_settings, net_settings, sdn_image,
+                                 APEX_TEMP_DIR, root_pw=root_pw)
+        else:
+            shutil.copyfile(sdn_image, os.path.join(APEX_TEMP_DIR,
+                                                    'overcloud-full.qcow2'))
+            shutil.copyfile(
+                opnfv_env,
+                os.path.join(APEX_TEMP_DIR, os.path.basename(opnfv_env))
+            )
+
+        oc_deploy.create_deploy_cmd(deploy_settings, net_settings, inventory,
+                                    APEX_TEMP_DIR, args.virtual,
+                                    os.path.basename(opnfv_env),
+                                    net_data=net_data)
+        deploy_playbook = os.path.join(args.lib_dir, ANSIBLE_PATH,
                                        'deploy_overcloud.yml')
         virt_env = 'virtual-environment.yaml'
         bm_env = 'baremetal-environment.yaml'
@@ -345,10 +438,19 @@ def main():
         deploy_vars = dict()
         deploy_vars['virtual'] = args.virtual
         deploy_vars['debug'] = args.debug
+        deploy_vars['aarch64'] = platform.machine() == 'aarch64'
+        deploy_vars['introspect'] = not (args.virtual or
+                                         deploy_vars['aarch64'] or
+                                         not introspect)
         deploy_vars['dns_server_args'] = ''
         deploy_vars['apex_temp_dir'] = APEX_TEMP_DIR
+        deploy_vars['apex_env_file'] = os.path.basename(opnfv_env)
         deploy_vars['stackrc'] = 'source /home/stack/stackrc'
         deploy_vars['overcloudrc'] = 'source /home/stack/overcloudrc'
+        deploy_vars['upstream'] = upstream
+        deploy_vars['os_version'] = os_version
+        deploy_vars['http_proxy'] = net_settings.get('http_proxy', '')
+        deploy_vars['https_proxy'] = net_settings.get('https_proxy', '')
         for dns_server in net_settings['dns_servers']:
             deploy_vars['dns_server_args'] += " --dns-nameserver {}".format(
                 dns_server)
@@ -356,10 +458,11 @@ def main():
             utils.run_ansible(deploy_vars, deploy_playbook, host=undercloud.ip,
                               user='stack', tmp_dir=APEX_TEMP_DIR)
             logging.info("Overcloud deployment complete")
-            os.remove(os.path.join(APEX_TEMP_DIR, 'overcloud-full.qcow2'))
         except Exception:
             logging.error("Deployment Failed.  Please check log")
             raise
+        finally:
+            os.remove(os.path.join(APEX_TEMP_DIR, 'overcloud-full.qcow2'))
 
         # Post install
         logging.info("Executing post deploy configuration")
@@ -372,9 +475,8 @@ def main():
                                      'UserKnownHostsFile=/dev/null -o ' \
                                      'LogLevel=error'
         deploy_vars['external_network_cmds'] = \
-            overcloud_deploy.external_network_cmds(net_settings)
+            oc_deploy.external_network_cmds(net_settings)
         # TODO(trozet): just parse all ds_opts as deploy vars one time
-        ds_opts = deploy_settings['deploy_options']
         deploy_vars['gluon'] = ds_opts['gluon']
         deploy_vars['sdn'] = ds_opts['sdn_controller']
         for dep_option in 'yardstick', 'dovetail', 'vsperf':
@@ -386,10 +488,13 @@ def main():
         overcloudrc = os.path.join(APEX_TEMP_DIR, 'overcloudrc')
         if ds_opts['congress']:
             deploy_vars['congress_datasources'] = \
-                overcloud_deploy.create_congress_cmds(overcloudrc)
+                oc_deploy.create_congress_cmds(overcloudrc)
             deploy_vars['congress'] = True
         else:
             deploy_vars['congress'] = False
+        deploy_vars['calipso'] = ds_opts.get('calipso', False)
+        deploy_vars['calipso_ip'] = net_settings['networks']['admin'][
+            'installer_vm']['ip']
         # TODO(trozet): this is probably redundant with getting external
         # network info from undercloud.py
         if 'external' in net_settings.enabled_network_list:
@@ -401,7 +506,7 @@ def main():
             deploy_vars['external_network_ipv6'] = True
         else:
             deploy_vars['external_network_ipv6'] = False
-        post_undercloud = os.path.join(args.lib_dir, ansible_path,
+        post_undercloud = os.path.join(args.lib_dir, ANSIBLE_PATH,
                                        'post_deploy_undercloud.yml')
         logging.info("Executing post deploy configuration undercloud playbook")
         try:
@@ -416,9 +521,10 @@ def main():
         # TODO(trozet): just parse all ds_opts as deploy vars one time
         deploy_vars['sfc'] = ds_opts['sfc']
         deploy_vars['vpn'] = ds_opts['vpn']
+        deploy_vars['l2gw'] = ds_opts.get('l2gw')
         # TODO(trozet): pull all logs and store in tmp dir in overcloud
         # playbook
-        post_overcloud = os.path.join(args.lib_dir, ansible_path,
+        post_overcloud = os.path.join(args.lib_dir, ANSIBLE_PATH,
                                       'post_deploy_overcloud.yml')
         # Run per overcloud node
         for node, ip in deploy_vars['overcloud_nodes'].items():
@@ -437,5 +543,7 @@ def main():
         logging.info("Undercloud IP: {}, please connect by doing "
                      "'opnfv-util undercloud'".format(undercloud.ip))
         # TODO(trozet): add logging here showing controller VIP and horizon url
+
+
 if __name__ == '__main__':
     main()