summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Little <scott.little@windriver.com>2018-08-07 11:51:21 -0400
committerScott Little <scott.little@windriver.com>2018-08-07 11:51:21 -0400
commite82c7b43362bceb8d4ae9d121d023e42268204db (patch)
tree8cf3094d57a9a14cdfd1898d1f77497917a5ce78
StarlingX open source release updates2018.08.0m/2018.08
Signed-off-by: Scott Little <scott.little@windriver.com>
-rw-r--r--.coveragerc12
-rw-r--r--.coveragerc_xml11
-rw-r--r--.gitignore57
-rw-r--r--.mailmap3
-rw-r--r--.testr.conf14
-rw-r--r--CONTRIBUTING.rst14
-rw-r--r--CONTRIBUTORS.wrs20
-rw-r--r--HACKING.rst4
-rw-r--r--LICENSE176
-rw-r--r--MANIFEST.in9
-rw-r--r--README.rst6
-rw-r--r--README_DC58
-rw-r--r--babel.cfg2
-rw-r--r--dcmanager/__init__.py25
-rwxr-xr-xdcmanager/api/README.rst31
-rw-r--r--dcmanager/api/__init__.py0
-rw-r--r--dcmanager/api/api_config.py111
-rw-r--r--dcmanager/api/app.py97
-rwxr-xr-xdcmanager/api/controllers/README.rst14
-rw-r--r--dcmanager/api/controllers/__init__.py0
-rw-r--r--dcmanager/api/controllers/restcomm.py48
-rw-r--r--dcmanager/api/controllers/root.py64
-rw-r--r--dcmanager/api/controllers/v1/__init__.py0
-rw-r--r--dcmanager/api/controllers/v1/alarm_manager.py87
-rw-r--r--dcmanager/api/controllers/v1/root.py63
-rw-r--r--dcmanager/api/controllers/v1/subclouds.py688
-rw-r--r--dcmanager/api/controllers/v1/sw_update_options.py244
-rwxr-xr-xdcmanager/api/controllers/v1/sw_update_strategy.py196
-rw-r--r--dcmanager/api/enforcer.py78
-rwxr-xr-xdcmanager/cmd/README.rst18
-rw-r--r--dcmanager/cmd/__init__.py0
-rw-r--r--dcmanager/cmd/api.py78
-rw-r--r--dcmanager/cmd/manage.py85
-rw-r--r--dcmanager/cmd/manager.py64
-rw-r--r--dcmanager/common/__init__.py0
-rw-r--r--dcmanager/common/config.py159
-rw-r--r--dcmanager/common/consts.py90
-rw-r--r--dcmanager/common/context.py154
-rw-r--r--dcmanager/common/exceptions.py148
-rw-r--r--dcmanager/common/i18n.py27
-rw-r--r--dcmanager/common/manager.py124
-rw-r--r--dcmanager/common/messaging.py118
-rw-r--r--dcmanager/common/policy.py56
-rw-r--r--dcmanager/common/serializer.py89
-rw-r--r--dcmanager/common/utils.py91
-rw-r--r--dcmanager/common/version.py48
-rw-r--r--dcmanager/config-generator.conf15
-rw-r--r--dcmanager/db/__init__.py0
-rw-r--r--dcmanager/db/api.py394
-rw-r--r--dcmanager/db/sqlalchemy/__init__.py0
-rw-r--r--dcmanager/db/sqlalchemy/api.py602
-rw-r--r--dcmanager/db/sqlalchemy/migrate_repo/README4
-rw-r--r--dcmanager/db/sqlalchemy/migrate_repo/__init__.py0
-rw-r--r--dcmanager/db/sqlalchemy/migrate_repo/manage.py5
-rw-r--r--dcmanager/db/sqlalchemy/migrate_repo/migrate.cfg25
-rw-r--r--dcmanager/db/sqlalchemy/migrate_repo/versions/001_first_version.py197
-rw-r--r--dcmanager/db/sqlalchemy/migrate_repo/versions/__init__.py0
-rw-r--r--dcmanager/db/sqlalchemy/migration.py47
-rw-r--r--dcmanager/db/sqlalchemy/models.py169
-rw-r--r--dcmanager/db/utils.py55
-rw-r--r--dcmanager/drivers/README.rst5
-rw-r--r--dcmanager/drivers/__init__.py0
-rw-r--r--dcmanager/drivers/base.py31
-rw-r--r--dcmanager/drivers/openstack/__init__.py0
-rw-r--r--dcmanager/drivers/openstack/patching_v1.py196
-rw-r--r--dcmanager/drivers/openstack/sysinv_v1.py124
-rw-r--r--dcmanager/drivers/openstack/vim.py157
-rwxr-xr-xdcmanager/manager/README.rst23
-rw-r--r--dcmanager/manager/__init__.py0
-rw-r--r--dcmanager/manager/patch_audit_manager.py248
-rw-r--r--dcmanager/manager/scheduler.py91
-rw-r--r--dcmanager/manager/service.py236
-rw-r--r--dcmanager/manager/subcloud_audit_manager.py259
-rw-r--r--dcmanager/manager/subcloud_manager.py590
-rw-r--r--dcmanager/manager/sw_update_manager.py1483
-rw-r--r--dcmanager/objects/__init__.py0
-rw-r--r--dcmanager/objects/base.py76
-rw-r--r--dcmanager/rpc/__init__.py0
-rw-r--r--dcmanager/rpc/client.py102
-rw-r--r--dcmanager/tests/__init__.py0
-rw-r--r--dcmanager/tests/base.py27
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/dcmanager/migrate_version.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/dcmanager/strategy_steps.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/dcmanager/subcloud_status.json17
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/dcmanager/subclouds.json5
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/dcmanager/sw_update_opts_default.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/dcmanager/sw_update_strategy.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/assignment.json30
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/endpoint.json185
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/local_user.json24
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/migrate_version.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/password.json24
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/project.json9
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/region.json7
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/revocation_event.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/role.json7
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/service.json20
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/strategy_steps.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/subcloud_status.json17
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/subclouds.json5
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/sw_update_opts_default.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/sw_update_strategy.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/trust.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/trust_role.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/keystone/user.json24
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/subclouds.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/address_modes.json8
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/address_pool_ranges.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/address_pools.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/addresses.json19
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/clusters.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/controller_fs.json9
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/drbdconfig.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/ethernet_interfaces.json18
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/ethernet_ports.json18
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/event_suppression.json92
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/host_upgrade.json4
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_alarm.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_dns.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_event_log.json4002
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_host.json4
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_icpu.json90
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_idisk.json8
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_imemory.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_lvg.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_node.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_ntp.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_pv.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_sensorgroups.json10
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_sensorgroups_discrete.json10
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_sensors.json78
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_sensors_discrete.json78
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_system.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/i_user.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/interfaces.json20
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/interfaces_to_interfaces.json4
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/lldp_agents.json18
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/lldp_neighbours.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/lldp_tlvs.json198
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/loads.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/migrate_version.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/networks.json6
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/partition.json12
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/pci_devices.json40
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/ports.json18
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/remotelogging.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/routes.json8
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/service_parameter.json26
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/services.json7
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/storage_backend.json4
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/storage_file.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/storage_lvm.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/storage_tiers.json3
-rw-r--r--dcmanager/tests/data/ipv6_R5_install/sysinv/vlan_interfaces.json4
-rw-r--r--dcmanager/tests/unit/__init__.py0
-rw-r--r--dcmanager/tests/unit/api/__init__.py0
-rw-r--r--dcmanager/tests/unit/api/test_root_controller.py160
-rw-r--r--dcmanager/tests/unit/api/v1/__init__.py0
-rw-r--r--dcmanager/tests/unit/api/v1/controllers/__init__.py0
-rw-r--r--dcmanager/tests/unit/api/v1/controllers/test_subclouds.py271
-rw-r--r--dcmanager/tests/unit/api/v1/controllers/test_sw_update_strategy.py179
-rw-r--r--dcmanager/tests/unit/common/__init__.py0
-rw-r--r--dcmanager/tests/unit/common/test_endpoint_cache.py124
-rw-r--r--dcmanager/tests/unit/db/__init__.py0
-rw-r--r--dcmanager/tests/unit/db/test_subcloud_db_api.py601
-rw-r--r--dcmanager/tests/unit/drivers/__init__.py0
-rw-r--r--dcmanager/tests/unit/drivers/test_keystone_v3.py126
-rw-r--r--dcmanager/tests/unit/drivers/test_sysinv_v1.py127
-rw-r--r--dcmanager/tests/unit/manager/__init__.py0
-rw-r--r--dcmanager/tests/unit/manager/test_patch_audit_manager.py355
-rw-r--r--dcmanager/tests/unit/manager/test_service.py152
-rw-r--r--dcmanager/tests/unit/manager/test_subcloud_audit_manager.py79
-rw-r--r--dcmanager/tests/unit/manager/test_subcloud_manager.py178
-rw-r--r--dcmanager/tests/unit/manager/test_sw_update_manager.py834
-rw-r--r--dcmanager/tests/unit/objects/__init__.py0
-rw-r--r--dcmanager/tests/unit/objects/test_base.py67
-rw-r--r--dcmanager/tests/unit/rpc/__init__.py0
-rw-r--r--dcmanager/tests/unit/rpc/test_rpc_client.py94
-rw-r--r--dcmanager/tests/unit/test_dcmanager.py34
-rw-r--r--dcmanager/tests/unit/utils/test_utils.py30
-rw-r--r--dcmanager/tests/utils.py155
-rw-r--r--dcmanager/version.py23
-rw-r--r--dcorch/__init__.py19
-rwxr-xr-xdcorch/api/README.rst31
-rw-r--r--dcorch/api/__init__.py0
-rw-r--r--dcorch/api/api_config.py101
-rw-r--r--dcorch/api/app.py101
-rwxr-xr-xdcorch/api/controllers/README.rst14
-rw-r--r--dcorch/api/controllers/__init__.py0
-rw-r--r--dcorch/api/controllers/restcomm.py43
-rw-r--r--dcorch/api/controllers/root.py57
-rw-r--r--dcorch/api/controllers/v1/__init__.py0
-rw-r--r--dcorch/api/controllers/v1/alarm_manager.py85
-rw-r--r--dcorch/api/controllers/v1/root.py50
-rw-r--r--dcorch/api/controllers/v1/subcloud_manager.py93
-rw-r--r--dcorch/api/enforcer.py71
-rw-r--r--dcorch/api/proxy/__init__.py0
-rw-r--r--dcorch/api/proxy/apps/__init__.py0
-rw-r--r--dcorch/api/proxy/apps/acceptor.py123
-rw-r--r--dcorch/api/proxy/apps/controller.py649
-rw-r--r--dcorch/api/proxy/apps/dispatcher.py57
-rw-r--r--dcorch/api/proxy/apps/filter.py63
-rw-r--r--dcorch/api/proxy/apps/patch.py225
-rw-r--r--dcorch/api/proxy/apps/proxy.py37
-rw-r--r--dcorch/api/proxy/apps/router.py86
-rw-r--r--dcorch/api/proxy/common/__init__.py0
-rwxr-xr-xdcorch/api/proxy/common/constants.py368
-rw-r--r--dcorch/api/proxy/common/service.py91
-rw-r--r--dcorch/api/proxy/common/utils.py110
-rwxr-xr-xdcorch/cmd/README.rst18
-rw-r--r--dcorch/cmd/__init__.py0
-rw-r--r--dcorch/cmd/api.py70
-rw-r--r--dcorch/cmd/api_proxy.py100
-rw-r--r--dcorch/cmd/engine.py55
-rw-r--r--dcorch/cmd/manage.py78
-rw-r--r--dcorch/cmd/snmp.py42
-rw-r--r--dcorch/common/__init__.py0
-rw-r--r--dcorch/common/config.py230
-rw-r--r--dcorch/common/consts.py180
-rw-r--r--dcorch/common/context.py147
-rw-r--r--dcorch/common/endpoint_cache.py178
-rw-r--r--dcorch/common/exceptions.py211
-rw-r--r--dcorch/common/i18n.py20
-rw-r--r--dcorch/common/manager.py117
-rw-r--r--dcorch/common/messaging.py111
-rw-r--r--dcorch/common/policy.py49
-rw-r--r--dcorch/common/serializer.py82
-rw-r--r--dcorch/common/utils.py184
-rw-r--r--dcorch/common/version.py41
-rw-r--r--dcorch/config-generator.conf15
-rw-r--r--dcorch/db/__init__.py0
-rw-r--r--dcorch/db/api.py312
-rw-r--r--dcorch/db/sqlalchemy/__init__.py0
-rw-r--r--dcorch/db/sqlalchemy/api.py953
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/README4
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/__init__.py0
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/manage.py5
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/migrate.cfg25
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/versions/001_initial.py131
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/versions/002_orch.py222
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/versions/003_placeholder.py16
-rw-r--r--dcorch/db/sqlalchemy/migrate_repo/versions/__init__.py0
-rw-r--r--dcorch/db/sqlalchemy/migration.py40
-rw-r--r--dcorch/db/sqlalchemy/models.py316
-rw-r--r--dcorch/db/utils.py48
-rw-r--r--dcorch/drivers/README.rst5
-rw-r--r--dcorch/drivers/__init__.py0
-rw-r--r--dcorch/drivers/base.py55
-rw-r--r--dcorch/drivers/openstack/__init__.py0
-rw-r--r--dcorch/drivers/openstack/cinder_v2.py88
-rw-r--r--dcorch/drivers/openstack/keystone_v3.py137
-rw-r--r--dcorch/drivers/openstack/neutron_v2.py132
-rw-r--r--dcorch/drivers/openstack/nova_v2.py151
-rw-r--r--dcorch/drivers/openstack/sdk.py322
-rw-r--r--dcorch/drivers/openstack/sdk_platform.py131
-rw-r--r--dcorch/drivers/openstack/sysinv_v1.py710
-rwxr-xr-xdcorch/engine/README.rst17
-rw-r--r--dcorch/engine/__init__.py7
-rw-r--r--dcorch/engine/alarm_aggregate_manager.py160
-rw-r--r--dcorch/engine/dc_orch_lock.py94
-rw-r--r--dcorch/engine/generic_sync_manager.py90
-rw-r--r--dcorch/engine/quota_manager.py491
-rw-r--r--dcorch/engine/scheduler.py104
-rw-r--r--dcorch/engine/service.py235
-rw-r--r--dcorch/engine/subcloud.py113
-rw-r--r--dcorch/engine/sync_services/__init__.py0
-rw-r--r--dcorch/engine/sync_services/compute.py737
-rw-r--r--dcorch/engine/sync_services/identity.py862
-rw-r--r--dcorch/engine/sync_services/network.py486
-rw-r--r--dcorch/engine/sync_services/sysinv.py1263
-rw-r--r--dcorch/engine/sync_services/volume.py258
-rw-r--r--dcorch/engine/sync_thread.py726
-rw-r--r--dcorch/objects/__init__.py0
-rw-r--r--dcorch/objects/base.py77
-rw-r--r--dcorch/objects/orchjob.py90
-rw-r--r--dcorch/objects/orchrequest.py118
-rw-r--r--dcorch/objects/resource.py91
-rw-r--r--dcorch/objects/service.py63
-rw-r--r--dcorch/objects/subcloud.py99
-rw-r--r--dcorch/objects/subcloud_resource.py102
-rw-r--r--dcorch/rpc/__init__.py0
-rw-r--r--dcorch/rpc/client.py120
-rwxr-xr-xdcorch/snmp/README.rst9
-rw-r--r--dcorch/snmp/__init__.py0
-rw-r--r--dcorch/snmp/controller.py105
-rw-r--r--dcorch/snmp/queue_monitor.py56
-rw-r--r--dcorch/snmp/service.py46
-rw-r--r--dcorch/snmp/snmp_config.py101
-rw-r--r--dcorch/snmp/snmp_server.py102
-rw-r--r--dcorch/tests/__init__.py0
-rw-r--r--dcorch/tests/base.py20
-rw-r--r--dcorch/tests/data/ipv6_R5_install/dcmanager/migrate_version.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/dcmanager/strategy_steps.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/dcmanager/subcloud_status.json17
-rw-r--r--dcorch/tests/data/ipv6_R5_install/dcmanager/subclouds.json5
-rw-r--r--dcorch/tests/data/ipv6_R5_install/dcmanager/sw_update_opts_default.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/dcmanager/sw_update_strategy.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/assignment.json30
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/endpoint.json185
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/local_user.json24
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/migrate_version.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/password.json24
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/project.json9
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/region.json7
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/revocation_event.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/role.json7
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/service.json20
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/strategy_steps.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/subcloud_status.json17
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/subclouds.json5
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/sw_update_opts_default.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/sw_update_strategy.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/trust.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/trust_role.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/keystone/user.json24
-rw-r--r--dcorch/tests/data/ipv6_R5_install/subclouds.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/address_modes.json8
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/address_pool_ranges.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/address_pools.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/addresses.json19
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/clusters.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/controller_fs.json9
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/drbdconfig.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/ethernet_interfaces.json18
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/ethernet_ports.json18
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/event_suppression.json92
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/host_upgrade.json4
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_alarm.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_dns.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_event_log.json4002
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_host.json4
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_icpu.json90
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_idisk.json8
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_imemory.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_lvg.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_node.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_ntp.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_pv.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_sensorgroups.json10
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_sensorgroups_discrete.json10
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_sensors.json78
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_sensors_discrete.json78
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_system.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/i_user.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/interfaces.json20
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/interfaces_to_interfaces.json4
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/lldp_agents.json18
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/lldp_neighbours.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/lldp_tlvs.json198
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/loads.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/migrate_version.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/networks.json6
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/partition.json12
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/pci_devices.json40
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/ports.json18
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/remotelogging.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/routes.json8
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/service_parameter.json26
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/services.json7
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/storage_backend.json4
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/storage_file.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/storage_lvm.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/storage_tiers.json3
-rw-r--r--dcorch/tests/data/ipv6_R5_install/sysinv/vlan_interfaces.json4
-rw-r--r--dcorch/tests/unit/__init__.py0
-rw-r--r--dcorch/tests/unit/db/__init__.py0
-rw-r--r--dcorch/tests/unit/db/test_orch_request_db_api.py406
-rw-r--r--dcorch/tests/unit/db/test_subcloud_db_api.py205
-rw-r--r--dcorch/tests/unit/db/test_subcloud_resource_db_api.py250
-rw-r--r--dcorch/tests/utils.py97
-rw-r--r--dcorch/version.py16
-rw-r--r--etc/dcmanager/README-dcmanager.conf.txt4
-rwxr-xr-xetc/dcmanager/policy.json7
-rw-r--r--etc/dcorch/README-dcorch.conf.txt4
-rwxr-xr-xetc/dcorch/policy.json7
-rw-r--r--pylint.rc218
-rw-r--r--requirements.txt50
-rw-r--r--setup.cfg51
-rw-r--r--setup.py30
-rw-r--r--setup_ddt_tests.py108
-rw-r--r--test-requirements.txt22
-rw-r--r--tox.ini98
382 files changed, 39495 insertions, 0 deletions
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..7919d15
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,12 @@
1[run]
2branch = True
3parallel = True
4source =
5 dcmanager
6 dcorch
7
8[report]
9ignore_errors = True
10omit =
11 */tests/*
12
diff --git a/.coveragerc_xml b/.coveragerc_xml
new file mode 100644
index 0000000..74ad816
--- /dev/null
+++ b/.coveragerc_xml
@@ -0,0 +1,11 @@
1[run]
2branch = True
3parallel = True
4source =
5 distributedcloud
6
7[report]
8ignore_errors = True
9omit =
10 */tests/*
11
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6daaa99
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,57 @@
1*.py[cod]
2
3# C extensions
4*.so
5
6# Packages
7*.egg
8*.egg-info
9dist
10build
11eggs
12parts
13var
14sdist
15develop-eggs
16.installed.cfg
17lib
18lib64
19
20# Installer logs
21pip-log.txt
22
23# Unit test / coverage reports
24.coverage
25cover
26coverage.xml
27.coverage\.*
28.current.cfg
29.tox
30nosetests.xml
31.testrepository
32.venv
33
34# Translations
35*.mo
36
37# Mr Developer
38.mr.developer.cfg
39.project
40.pydevproject
41
42# Complexity
43output/*.html
44output/*/index.html
45
46# Sphinx
47doc/build
48
49# pbr generates these
50AUTHORS
51ChangeLog
52
53# Editors
54*~
55.*.swp
56.*sw?
57
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..c6e0723
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,3 @@
1# Format is:
2# <preferred e-mail> <other e-mail 1>
3Dimitri Mazmanov <dimitri.mazmanov@ericsson.com>
diff --git a/.testr.conf b/.testr.conf
new file mode 100644
index 0000000..7c167d7
--- /dev/null
+++ b/.testr.conf
@@ -0,0 +1,14 @@
1# The sed command is required for coverage to work.
2# otherwise testr will pass --source distributedcloud when invoking coverage
3# which breaks the source definitions in the .coveragerc file
4[DEFAULT]
5test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1}
6 OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1}
7 OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60}
8 PYTHON=$(echo ${PYTHON:-python} | sed 's/--source distributedcloud//g')
9 ${PYTHON} -m subunit.run discover -s dcmanager $LISTOPT $IDOPTION
10 ${PYTHON} -m subunit.run discover -s dcorch $LISTOPT $IDOPTION
11test_id_option=--load-list $IDFILE
12test_list_option=--list
13test_run_concurrency=echo 5
14
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000..5f31096
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,14 @@
1If you would like to contribute to the development of OpenStack, you must
2follow the steps in this page:
3
4 http://docs.openstack.org/infra/manual/developers.html
5
6If you already have a good understanding of how the system works and your
7OpenStack accounts are set up, you can skip to the development workflow
8section of this documentation to learn how changes to OpenStack should be
9submitted for review via the Gerrit tool:
10
11 http://docs.openstack.org/infra/manual/developers.html#development-workflow
12
13Pull requests submitted through GitHub will be ignored.
14
diff --git a/CONTRIBUTORS.wrs b/CONTRIBUTORS.wrs
new file mode 100644
index 0000000..01f3eb4
--- /dev/null
+++ b/CONTRIBUTORS.wrs
@@ -0,0 +1,20 @@
1The following contributors from Wind River have developed the seed code in this
2repository. We look forward to community collaboration and contributions for
3additional features, enhancements and refactoring.
4Contributors:
5=============
6Al Bailey
7Alex Kozyrev
8Andy Ning
9Angie Wang
10Bart Wensley
11Chris Friesen
12John Kung
13Kam Nasim
14Kevin Smith
15Lachlan Plant
16Saju Oommen
17Stefan Dinescu
18Tao Liu
19Tyler Smith
20
diff --git a/HACKING.rst b/HACKING.rst
new file mode 100644
index 0000000..e49c273
--- /dev/null
+++ b/HACKING.rst
@@ -0,0 +1,4 @@
1DistributedCloud Style Commandments
2===============================================
3
4Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..68c771a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,176 @@
1
2 Apache License
3 Version 2.0, January 2004
4 http://www.apache.org/licenses/
5
6 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
8 1. Definitions.
9
10 "License" shall mean the terms and conditions for use, reproduction,
11 and distribution as defined by Sections 1 through 9 of this document.
12
13 "Licensor" shall mean the copyright owner or entity authorized by
14 the copyright owner that is granting the License.
15
16 "Legal Entity" shall mean the union of the acting entity and all
17 other entities that control, are controlled by, or are under common
18 control with that entity. For the purposes of this definition,
19 "control" means (i) the power, direct or indirect, to cause the
20 direction or management of such entity, whether by contract or
21 otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 outstanding shares, or (iii) beneficial ownership of such entity.
23
24 "You" (or "Your") shall mean an individual or Legal Entity
25 exercising permissions granted by this License.
26
27 "Source" form shall mean the preferred form for making modifications,
28 including but not limited to software source code, documentation
29 source, and configuration files.
30
31 "Object" form shall mean any form resulting from mechanical
32 transformation or translation of a Source form, including but
33 not limited to compiled object code, generated documentation,
34 and conversions to other media types.
35
36 "Work" shall mean the work of authorship, whether in Source or
37 Object form, made available under the License, as indicated by a
38 copyright notice that is included in or attached to the work
39 (an example is provided in the Appendix below).
40
41 "Derivative Works" shall mean any work, whether in Source or Object
42 form, that is based on (or derived from) the Work and for which the
43 editorial revisions, annotations, elaborations, or other modifications
44 represent, as a whole, an original work of authorship. For the purposes
45 of this License, Derivative Works shall not include works that remain
46 separable from, or merely link (or bind by name) to the interfaces of,
47 the Work and Derivative Works thereof.
48
49 "Contribution" shall mean any work of authorship, including
50 the original version of the Work and any modifications or additions
51 to that Work or Derivative Works thereof, that is intentionally
52 submitted to Licensor for inclusion in the Work by the copyright owner
53 or by an individual or Legal Entity authorized to submit on behalf of
54 the copyright owner. For the purposes of this definition, "submitted"
55 means any form of electronic, verbal, or written communication sent
56 to the Licensor or its representatives, including but not limited to
57 communication on electronic mailing lists, source code control systems,
58 and issue tracking systems that are managed by, or on behalf of, the
59 Licensor for the purpose of discussing and improving the Work, but
60 excluding communication that is conspicuously marked or otherwise
61 designated in writing by the copyright owner as "Not a Contribution."
62
63 "Contributor" shall mean Licensor and any individual or Legal Entity
64 on behalf of whom a Contribution has been received by Licensor and
65 subsequently incorporated within the Work.
66
67 2. Grant of Copyright License. Subject to the terms and conditions of
68 this License, each Contributor hereby grants to You a perpetual,
69 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 copyright license to reproduce, prepare Derivative Works of,
71 publicly display, publicly perform, sublicense, and distribute the
72 Work and such Derivative Works in Source or Object form.
73
74 3. Grant of Patent License. Subject to the terms and conditions of
75 this License, each Contributor hereby grants to You a perpetual,
76 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 (except as stated in this section) patent license to make, have made,
78 use, offer to sell, sell, import, and otherwise transfer the Work,
79 where such license applies only to those patent claims licensable
80 by such Contributor that are necessarily infringed by their
81 Contribution(s) alone or by combination of their Contribution(s)
82 with the Work to which such Contribution(s) was submitted. If You
83 institute patent litigation against any entity (including a
84 cross-claim or counterclaim in a lawsuit) alleging that the Work
85 or a Contribution incorporated within the Work constitutes direct
86 or contributory patent infringement, then any patent licenses
87 granted to You under this License for that Work shall terminate
88 as of the date such litigation is filed.
89
90 4. Redistribution. You may reproduce and distribute copies of the
91 Work or Derivative Works thereof in any medium, with or without
92 modifications, and in Source or Object form, provided that You
93 meet the following conditions:
94
95 (a) You must give any other recipients of the Work or
96 Derivative Works a copy of this License; and
97
98 (b) You must cause any modified files to carry prominent notices
99 stating that You changed the files; and
100
101 (c) You must retain, in the Source form of any Derivative Works
102 that You distribute, all copyright, patent, trademark, and
103 attribution notices from the Source form of the Work,
104 excluding those notices that do not pertain to any part of
105 the Derivative Works; and
106
107 (d) If the Work includes a "NOTICE" text file as part of its
108 distribution, then any Derivative Works that You distribute must
109 include a readable copy of the attribution notices contained
110 within such NOTICE file, excluding those notices that do not
111 pertain to any part of the Derivative Works, in at least one
112 of the following places: within a NOTICE text file distributed
113 as part of the Derivative Works; within the Source form or
114 documentation, if provided along with the Derivative Works; or,
115 within a display generated by the Derivative Works, if and
116 wherever such third-party notices normally appear. The contents
117 of the NOTICE file are for informational purposes only and
118 do not modify the License. You may add Your own attribution
119 notices within Derivative Works that You distribute, alongside
120 or as an addendum to the NOTICE text from the Work, provided
121 that such additional attribution notices cannot be construed
122 as modifying the License.
123
124 You may add Your own copyright statement to Your modifications and
125 may provide additional or different license terms and conditions
126 for use, reproduction, or distribution of Your modifications, or
127 for any such Derivative Works as a whole, provided Your use,
128 reproduction, and distribution of the Work otherwise complies with
129 the conditions stated in this License.
130
131 5. Submission of Contributions. Unless You explicitly state otherwise,
132 any Contribution intentionally submitted for inclusion in the Work
133 by You to the Licensor shall be under the terms and conditions of
134 this License, without any additional terms or conditions.
135 Notwithstanding the above, nothing herein shall supersede or modify
136 the terms of any separate license agreement you may have executed
137 with Licensor regarding such Contributions.
138
139 6. Trademarks. This License does not grant permission to use the trade
140 names, trademarks, service marks, or product names of the Licensor,
141 except as required for reasonable and customary use in describing the
142 origin of the Work and reproducing the content of the NOTICE file.
143
144 7. Disclaimer of Warranty. Unless required by applicable law or
145 agreed to in writing, Licensor provides the Work (and each
146 Contributor provides its Contributions) on an "AS IS" BASIS,
147 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 implied, including, without limitation, any warranties or conditions
149 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 PARTICULAR PURPOSE. You are solely responsible for determining the
151 appropriateness of using or redistributing the Work and assume any
152 risks associated with Your exercise of permissions under this License.
153
154 8. Limitation of Liability. In no event and under no legal theory,
155 whether in tort (including negligence), contract, or otherwise,
156 unless required by applicable law (such as deliberate and grossly
157 negligent acts) or agreed to in writing, shall any Contributor be
158 liable to You for damages, including any direct, indirect, special,
159 incidental, or consequential damages of any character arising as a
160 result of this License or out of the use or inability to use the
161 Work (including but not limited to damages for loss of goodwill,
162 work stoppage, computer failure or malfunction, or any and all
163 other commercial damages or losses), even if such Contributor
164 has been advised of the possibility of such damages.
165
166 9. Accepting Warranty or Additional Liability. While redistributing
167 the Work or Derivative Works thereof, You may choose to offer,
168 and charge a fee for, acceptance of support, warranty, indemnity,
169 or other liability obligations and/or rights consistent with this
170 License. However, in accepting such obligations, You may act only
171 on Your own behalf and on Your sole responsibility, not on behalf
172 of any other Contributor, and only if You agree to indemnify,
173 defend, and hold each Contributor harmless for any liability
174 incurred by, or claims asserted against, such Contributor by reason
175 of your accepting any such warranty or additional liability.
176
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..6414083
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,9 @@
1include AUTHORS
2include ChangeLog
3include dcmanager/db/sqlalchemy/migrate_repo/migrate.cfg
4include dcorch/db/sqlalchemy/migrate_repo/migrate.cfg
5exclude .gitignore
6exclude .gitreview
7exclude .current.cfg
8
9global-exclude *.pyc
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..7aa9c1c
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,6 @@
1DistributedCloud
2===============================
3
4Wind River's Distributed Cloud system supports an edge computing solution by providing
5central management and orchestration for a geographically distributed network of Titanium
6Cloud systems.
diff --git a/README_DC b/README_DC
new file mode 100644
index 0000000..7a2b71b
--- /dev/null
+++ b/README_DC
@@ -0,0 +1,58 @@
1# These are instructions for building and installing Distributed Cloud
2
3# Packages and configure script are now included in the load
4
5# Run configure script (on target - requires root privileges)
6
7configure_dc.sh
8
9# To use DC Manager CLI (these are just examples)
10
11source /etc/nova/openrc
12# Add subclouds (description and location are optional)
13dcmanager subcloud add --name=subcloud1 \
14 --description="subcloud1 description" \
15 --location="subcloud 1 location" \
16 --management-subnet=192.168.101.0/24 \
17 --management-start-ip=192.168.101.2 \
18 --management-end-ip=192.168.101.50 \
19 --management-gateway-ip=192.168.101.1 \
20 --systemcontroller-gateway-ip=192.168.204.101
21dcmanager subcloud add --name=subcloud2 \
22 --management-subnet=192.168.102.0/24 \
23 --management-start-ip=192.168.102.2 \
24 --management-end-ip=192.168.102.50 \
25 --management-gateway-ip=192.168.102.1 \
26 --systemcontroller-gateway-ip=192.168.204.101
27# List all subclouds
28dcmanager subcloud list
29# Show a single subcloud
30dcmanager subcloud show 1
31dcmanager subcloud show subcloud2
32# Update subcloud description or location
33dcmanager subcloud update 1 \
34 --description="new subcloud1 description" \
35 --location="new subcloud1 location"
36# Generate config for a subcloud (additional items are optional)
37dcmanager subcloud generate-config 1 \
38 --management-interface-port=enp0s8 \
39 --management-interface-mtu=1500 \
40 --oam-subnet=10.10.10.0/24 \
41 --oam-gateway-ip=10.10.10.1 \
42 --oam-floating-ip=10.10.10.12 \
43 --oam-unit-0-ip=10.10.10.13 \
44 --oam-unit-1-ip=10.10.10.14 \
45 --oam-interface-port=enp0s3 \
46 --oam-interface-mtu=1500
47dcmanager subcloud generate-config 2
48# Unlock a subcloud
49dcmanager subcloud unlock 1
50# Lock a subcloud
51dcmanager subcloud lock 1
52# Delete a subcloud (must be locked)
53dcmanager subcloud delete 1
54
55# To use DC Orchestrator API directly
56
57run "openstack token issue", then copy the token. Then to add a subcloud it's something like this:
58curl -H "Content-Type: application/json" -H "X-Auth-Token: gAAAAABZ3pT6ZLUaMJfTjAius1zFjcYq25JyiI-eHJe_m5B4NheiN_T94wbG-NrFAAbYNKkOb90MdQ5fnTMjGi1QqZyJ9Rkyg2ZvnaI3Sj8Cw6cSl7goyG0rzseP9b1qADmvX66aqZx79pQQUE0EcC2YDPh-mwgYRoerjuNQ_DGYeWOfZxa06kk " -X POST -d '{"subcloud":"subcloud2"}' http://127.0.0.1:8118/v1.0/d9f1bcfd50b447de993ec90614e9bdc8/subclouds
diff --git a/babel.cfg b/babel.cfg
new file mode 100644
index 0000000..15cd6cb
--- /dev/null
+++ b/babel.cfg
@@ -0,0 +1,2 @@
1[python: **.py]
2
diff --git a/dcmanager/__init__.py b/dcmanager/__init__.py
new file mode 100644
index 0000000..f66b26a
--- /dev/null
+++ b/dcmanager/__init__.py
@@ -0,0 +1,25 @@
1# -*- coding: utf-8 -*-
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14#
15# Copyright (c) 2017 Wind River Systems, Inc.
16#
17# The right to copy, distribute, modify, or otherwise make use
18# of this software may be licensed only pursuant to the terms
19# of an applicable Wind River license agreement.
20#
21
22import pbr.version
23
24
25__version__ = pbr.version.VersionInfo('distributedcloud').version_string()
diff --git a/dcmanager/api/README.rst b/dcmanager/api/README.rst
new file mode 100755
index 0000000..654c8c9
--- /dev/null
+++ b/dcmanager/api/README.rst
@@ -0,0 +1,31 @@
1===============================
2api
3===============================
4
5DC Manager API is Web Server Gateway Interface (WSGI) application to receive
6and process API calls, including keystonemiddleware to do the authentication,
7parameter check and validation, convert API calls to job rpc message, and
8then send the job to DC Manager Manager through the queue. If the job will
9be processed by DC Manager Manager in synchronous way, the DC Manager API will
10wait for the response from the DC Manager Manager. Otherwise, the DC Manager
11API will send response to the API caller first, and then send the job to
12DC Manager Manager in asynchronous way.
13
14Multiple DC Manager API could run in parallel, and also can work in
15multi-worker mode.
16
17Multiple DC Manager API will be designed and run in stateless mode, persistent
18data will be accessed (read and write) from the DC Manager Database through
19the DAL module.
20
21Setup and encapsulate the API WSGI app
22
23app.py:
24 Setup and encapsulate the API WSGI app, including integrate the
25 keystonemiddleware app
26
27api_config.py:
28 API configuration loading and init
29
30enforcer.py
31 Enforces policies on the version2 APIs
diff --git a/dcmanager/api/__init__.py b/dcmanager/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dcmanager/api/__init__.py
diff --git a/dcmanager/api/api_config.py b/dcmanager/api/api_config.py
new file mode 100644
index 0000000..3357a70
--- /dev/null
+++ b/dcmanager/api/api_config.py
@@ -0,0 +1,111 @@
1# Copyright 2015 Huawei Technologies Co., Ltd.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23"""
24Routines for configuring DC Manager, largely copy from Neutron
25"""
26
27import os
28import sys
29
30
31from oslo_config import cfg
32from oslo_log import log as logging
33
34from dcmanager.common.i18n import _
35
36
37# from dcmanager import policy
38from dcmanager.common import version
39
40LOG = logging.getLogger(__name__)
41
42common_opts = [
43 cfg.StrOpt('bind_host', default='0.0.0.0',
44 help=_("The host IP to bind to")),
45 cfg.IntOpt('bind_port', default=8119,
46 help=_("The port to bind to")),
47 cfg.IntOpt('api_workers', default=2,
48 help=_("number of api workers")),
49 cfg.StrOpt('state_path',
50 default=os.path.join(os.path.dirname(__file__), '../'),
51 help='Top-level directory for maintaining dcmanager state'),
52 cfg.StrOpt('api_extensions_path', default="",
53 help=_("The path for API extensions")),
54 cfg.StrOpt('auth_strategy', default='keystone',
55 help=_("The type of authentication to use")),
56 cfg.BoolOpt('allow_bulk', default=True,
57 help=_("Allow the usage of the bulk API")),
58 cfg.BoolOpt('allow_pagination', default=False,
59 help=_("Allow the usage of the pagination")),
60 cfg.BoolOpt('allow_sorting', default=False,
61 help=_("Allow the usage of the sorting")),
62 cfg.StrOpt('pagination_max_limit', default="-1",
63 help=_("The maximum number of items returned in a single "
64 "response, value was 'infinite' or negative integer "
65 "means no limit")),
66]
67
68
69def init(args, **kwargs):
70 # Register the configuration options
71 cfg.CONF.register_opts(common_opts)
72
73 # ks_session.Session.register_conf_options(cfg.CONF)
74 # auth.register_conf_options(cfg.CONF)
75 logging.register_options(cfg.CONF)
76
77 cfg.CONF(args=args, project='dcmanager',
78 version='%%(prog)s %s' % version.version_info.release_string(),
79 **kwargs)
80
81
82def setup_logging():
83 """Sets up the logging options for a log with supplied name."""
84 product_name = "dcmanager"
85 logging.setup(cfg.CONF, product_name)
86 LOG.info("Logging enabled!")
87 LOG.info("%(prog)s version %(version)s",
88 {'prog': sys.argv[0],
89 'version': version.version_info.release_string()})
90 LOG.debug("command line: %s", " ".join(sys.argv))
91
92
93def reset_service():
94 # Reset worker in case SIGHUP is called.
95 # Note that this is called only in case a service is running in
96 # daemon mode.
97 setup_logging()
98
99 # TODO(joehuang) enforce policy later
100 # policy.refresh()
101
102
103def test_init():
104 # Register the configuration options
105 cfg.CONF.register_opts(common_opts)
106 logging.register_options(cfg.CONF)
107 setup_logging()
108
109
110def list_opts():
111 yield None, common_opts
diff --git a/dcmanager/api/app.py b/dcmanager/api/app.py
new file mode 100644
index 0000000..fca8567
--- /dev/null
+++ b/dcmanager/api/app.py
@@ -0,0 +1,97 @@
1# Copyright (c) 2015 Huawei, Tech. Co,. Ltd.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23import pecan
24
25from keystonemiddleware import auth_token
26from oslo_config import cfg
27from oslo_middleware import request_id
28from oslo_service import service
29
30from dcmanager.common import context as ctx
31from dcmanager.common.i18n import _
32
33
34def setup_app(*args, **kwargs):
35
36 opts = cfg.CONF.pecan
37 config = {
38 'server': {
39 'port': cfg.CONF.bind_port,
40 'host': cfg.CONF.bind_host
41 },
42 'app': {
43 'root': 'dcmanager.api.controllers.root.RootController',
44 'modules': ['dcmanager.api'],
45 "debug": opts.debug,
46 "auth_enable": opts.auth_enable,
47 'errors': {
48 400: '/error',
49 '__force_dict__': True
50 }
51 }
52 }
53
54 pecan_config = pecan.configuration.conf_from_dict(config)
55
56 # app_hooks = [], hook collection will be put here later
57
58 app = pecan.make_app(
59 pecan_config.app.root,
60 debug=False,
61 wrap_app=_wrap_app,
62 force_canonical=False,
63 hooks=lambda: [ctx.AuthHook()],
64 guess_content_type_from_ext=True
65 )
66
67 return app
68
69
70def _wrap_app(app):
71 app = request_id.RequestId(app)
72 if cfg.CONF.pecan.auth_enable and cfg.CONF.auth_strategy == 'keystone':
73 conf = dict(cfg.CONF.keystone_authtoken)
74 # Change auth decisions of requests to the app itself.
75 conf.update({'delay_auth_decision': True})
76
77 # NOTE: Policy enforcement works only if Keystone
78 # authentication is enabled. No support for other authentication
79 # types at this point.
80 return auth_token.AuthProtocol(app, conf)
81 else:
82 return app
83
84
85_launcher = None
86
87
88def serve(api_service, conf, workers=1):
89 global _launcher
90 if _launcher:
91 raise RuntimeError(_('serve() can only be called once'))
92
93 _launcher = service.launch(conf, api_service, workers=workers)
94
95
96def wait():
97 _launcher.wait()
diff --git a/dcmanager/api/controllers/README.rst b/dcmanager/api/controllers/README.rst
new file mode 100755
index 0000000..c3d668e
--- /dev/null
+++ b/dcmanager/api/controllers/README.rst
@@ -0,0 +1,14 @@
1===============================
2controllers
3===============================
4
5API request processing
6
7root.py:
8 API root request
9
10subclouds.py
11 Controller for all the subcloud related requests
12
13restcomm.py:
14 common functionality used in API
diff --git a/dcmanager/api/controllers/__init__.py b/dcmanager/api/controllers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dcmanager/api/controllers/__init__.py
diff --git a/dcmanager/api/controllers/restcomm.py b/dcmanager/api/controllers/restcomm.py
new file mode 100644
index 0000000..9cd2320
--- /dev/null
+++ b/dcmanager/api/controllers/restcomm.py
@@ -0,0 +1,48 @@
1# Copyright (c) 2015 Huawei Tech. Co., Ltd.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23
24from pecan import request
25
26import dcmanager.common.context as k_context
27
28
29def extract_context_from_environ():
30 context_paras = {'auth_token': 'HTTP_X_AUTH_TOKEN',
31 'user': 'HTTP_X_USER_ID',
32 'project': 'HTTP_X_TENANT_ID',
33 'user_name': 'HTTP_X_USER_NAME',
34 'tenant_name': 'HTTP_X_PROJECT_NAME',
35 'domain': 'HTTP_X_DOMAIN_ID',
36 'roles': 'HTTP_X_ROLE',
37 'user_domain': 'HTTP_X_USER_DOMAIN_ID',
38 'project_domain': 'HTTP_X_PROJECT_DOMAIN_ID',
39 'request_id': 'openstack.request_id'}
40
41 environ = request.environ
42
43 for key in context_paras:
44 context_paras[key] = environ.get(context_paras[key])
45 role = environ.get('HTTP_X_ROLE')
46
47 context_paras['is_admin'] = 'admin' in role.split(',')
48 return k_context.RequestContext(**context_paras)
diff --git a/dcmanager/api/controllers/root.py b/dcmanager/api/controllers/root.py
new file mode 100644
index 0000000..a03246e
--- /dev/null
+++ b/dcmanager/api/controllers/root.py
@@ -0,0 +1,64 @@
1# Copyright (c) 2015 Huawei Tech. Co., Ltd.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23
24import pecan
25
26from dcmanager.api.controllers.v1 import root as v1_root
27
28
29class RootController(object):
30
31 @pecan.expose('json')
32 def _lookup(self, version, *remainder):
33 version = str(version)
34 minor_version = version[-1]
35 major_version = version[1]
36 remainder = remainder + (minor_version,)
37 if major_version == '1':
38 return v1_root.Controller(), remainder
39
40 @pecan.expose(generic=True, template='json')
41 def index(self):
42 return {
43 "versions": [
44 {
45 "status": "CURRENT",
46 "links": [
47 {
48 "rel": "self",
49 "href": pecan.request.application_url + "/v1.0/"
50 }
51 ],
52 "id": "v1.0",
53 "updated": "2017-10-2"
54 }
55 ]
56 }
57
58 @index.when(method='POST')
59 @index.when(method='PUT')
60 @index.when(method='DELETE')
61 @index.when(method='HEAD')
62 @index.when(method='PATCH')
63 def not_supported(self):
64 pecan.abort(405)
diff --git a/dcmanager/api/controllers/v1/__init__.py b/dcmanager/api/controllers/v1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dcmanager/api/controllers/v1/__init__.py
diff --git a/dcmanager/api/controllers/v1/alarm_manager.py b/dcmanager/api/controllers/v1/alarm_manager.py
new file mode 100644
index 0000000..f8890df
--- /dev/null
+++ b/dcmanager/api/controllers/v1/alarm_manager.py
@@ -0,0 +1,87 @@
1# Copyright (c) 2017 Ericsson AB.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23from dcmanager.api.controllers import restcomm
24from dcorch.rpc import client as dcorch_rpc_client
25from oslo_log import log as logging
26from pecan import expose
27
28LOG = logging.getLogger(__name__)
29
30
31class SubcloudAlarmController(object):
32 VERSION_ALIASES = {
33 'Newton': '1.0',
34 }
35
36 def __init__(self, *args, **kwargs):
37 super(SubcloudAlarmController, self).__init__(*args, **kwargs)
38 self.dcorch_rpc_client = dcorch_rpc_client.EngineClient()
39
40 # to do the version compatibility for future purpose
41 def _determine_version_cap(self, target):
42 version_cap = 1.0
43 return version_cap
44
45 @expose(generic=True, template='json')
46 def index(self):
47 # Route the request to specific methods with parameters
48 pass
49
50 def _get_alarm_aggregates(self):
51 summary = []
52 context = restcomm.extract_context_from_environ()
53 alarms = self.dcorch_rpc_client.get_alarm_summary(context)
54 for alarm in alarms:
55 alarm_dict = {'region_name': alarm['region_name'],
56 'uuid': alarm['uuid'],
57 'critical_alarms': alarm['critical_alarms'],
58 'major_alarms': alarm['major_alarms'],
59 'minor_alarms': alarm['minor_alarms'],
60 'warnings': alarm['warnings'],
61 'cloud_status': alarm['cloud_status']}
62 summary.append(alarm_dict)
63 return {'alarm_summary': summary}
64
65 @index.when(method='GET', template='json')
66 def get(self):
67 """Get List of alarm summarys
68
69 """
70 return self._get_alarm_aggregates()
71
72 def _get_alarm_summary(self):
73 alarms = self._get_alarm_aggregates()
74 summary = {'critical': 0,
75 'degraded': 0,
76 'ok': 0,
77 'unreachable': 0}
78 for alarm in alarms:
79 summary[alarm['cloud_status']] += 1
80 return summary
81
82 @index.when(method='summary', template='json')
83 def summary(self):
84 """Get an agregate of all subcloud status
85
86 """
87 return self._get_alarm_summary()
diff --git a/dcmanager/api/controllers/v1/root.py b/dcmanager/api/controllers/v1/root.py
new file mode 100644
index 0000000..9dc4c25
--- /dev/null
+++ b/dcmanager/api/controllers/v1/root.py
@@ -0,0 +1,63 @@
1# Copyright (c) 2017 Ericsson AB.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23
24from dcmanager.api.controllers.v1 import alarm_manager
25from dcmanager.api.controllers.v1 import subclouds
26from dcmanager.api.controllers.v1 import sw_update_options
27from dcmanager.api.controllers.v1 import sw_update_strategy
28
29import pecan
30
31
32class Controller(object):
33
34 def _get_resource_controller(self, remainder):
35
36 if not remainder:
37 pecan.abort(404)
38 return
39 minor_version = remainder[-1]
40 remainder = remainder[:-1]
41 sub_controllers = dict()
42 if minor_version == '0':
43 sub_controllers["subclouds"] = subclouds.SubcloudsController
44 sub_controllers["alarms"] = alarm_manager.SubcloudAlarmController
45 sub_controllers["sw-update-strategy"] = \
46 sw_update_strategy.SwUpdateStrategyController
47 sub_controllers["sw-update-options"] = \
48 sw_update_options.SwUpdateOptionsController
49
50 for name, ctrl in sub_controllers.items():
51 setattr(self, name, ctrl)
52
53 resource = remainder[0]
54 if resource not in sub_controllers:
55 pecan.abort(404)
56 return
57
58 remainder = remainder[1:]
59 return sub_controllers[resource](), remainder
60
61 @pecan.expose()
62 def _lookup(self, *remainder):
63 return self._get_resource_controller(remainder)
diff --git a/dcmanager/api/controllers/v1/subclouds.py b/dcmanager/api/controllers/v1/subclouds.py
new file mode 100644
index 0000000..2227850
--- /dev/null
+++ b/dcmanager/api/controllers/v1/subclouds.py
@@ -0,0 +1,688 @@
1# Copyright (c) 2017 Ericsson AB.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23import keyring
24from netaddr import IPAddress
25from netaddr import IPNetwork
26from netaddr import IPRange
27from oslo_config import cfg
28from oslo_log import log as logging
29from oslo_messaging import RemoteError
30
31import pecan
32from pecan import expose
33from pecan import request
34
35from configutilities.common import crypt
36from configutilities.common.exceptions import ValidateFail
37from configutilities.common.utils import validate_address_str
38from configutilities.common.utils import validate_network_str
39
40from dcorch.drivers.openstack.keystone_v3 import KeystoneClient
41
42from dcmanager.api.controllers import restcomm
43from dcmanager.common import consts
44from dcmanager.common import exceptions
45from dcmanager.common.i18n import _
46from dcmanager.db import api as db_api
47from dcmanager.drivers.openstack.sysinv_v1 import SysinvClient
48from dcmanager.rpc import client as rpc_client
49
50from Crypto.Hash import MD5
51import json
52
53CONF = cfg.CONF
54LOG = logging.getLogger(__name__)
55# System mode
56SYSTEM_MODE_DUPLEX = "duplex"
57SYSTEM_MODE_SIMPLEX = "simplex"
58SYSTEM_MODE_DUPLEX_DIRECT = "duplex-direct"
59
60
61class SubcloudsController(object):
62 VERSION_ALIASES = {
63 'Newton': '1.0',
64 }
65
66 def __init__(self):
67 super(SubcloudsController, self).__init__()
68 self.rpc_client = rpc_client.ManagerClient()
69
70 # to do the version compatibility for future purpose
71 def _determine_version_cap(self, target):
72 version_cap = 1.0
73 return version_cap
74
75 @expose(generic=True, template='json')
76 def index(self):
77 # Route the request to specific methods with parameters
78 pass
79
80 def _validate_subcloud_config(self,
81 context,
82 name,
83 management_subnet_str,
84 management_start_ip_str,
85 management_end_ip_str,
86 management_gateway_ip_str,
87 systemcontroller_gateway_ip_str):
88 """Check whether subcloud config is valid."""
89
90 # Validate the name
91 if name.isdigit():
92 pecan.abort(400, _("name must contain alphabetic characters"))
93
94 if name in [consts.DEFAULT_REGION_NAME,
95 consts.SYSTEM_CONTROLLER_NAME]:
96 pecan.abort(400, _("name cannot be %(bad_name1)s or %(bad_name2)s")
97 % {'bad_name1': consts.DEFAULT_REGION_NAME,
98 'bad_name2': consts.SYSTEM_CONTROLLER_NAME})
99
100 # Parse/validate the management subnet
101 subcloud_subnets = []
102 subclouds = db_api.subcloud_get_all(context)
103 for subcloud in subclouds:
104 subcloud_subnets.append(IPNetwork(subcloud.management_subnet))
105
106 MIN_MANAGEMENT_SUBNET_SIZE = 8
107 # subtract 3 for network, gateway and broadcast addresses.
108 MIN_MANAGEMENT_ADDRESSES = MIN_MANAGEMENT_SUBNET_SIZE - 3
109
110 management_subnet = None
111 try:
112 management_subnet = validate_network_str(
113 management_subnet_str,
114 minimum_size=MIN_MANAGEMENT_SUBNET_SIZE,
115 existing_networks=subcloud_subnets)
116 except ValidateFail as e:
117 LOG.exception(e)
118 pecan.abort(400, _("management-subnet invalid: %s") % e)
119
120 # Parse/validate the start/end addresses
121 management_start_ip = None
122 try:
123 management_start_ip = validate_address_str(
124 management_start_ip_str, management_subnet)
125 except ValidateFail as e:
126 LOG.exception(e)
127 pecan.abort(400, _("management-start-ip invalid: %s") % e)
128
129 management_end_ip = None
130 try:
131 management_end_ip = validate_address_str(
132 management_end_ip_str, management_subnet)
133 except ValidateFail as e:
134 LOG.exception(e)
135 pecan.abort(400, _("management-end-ip invalid: %s") % e)
136
137 if not management_start_ip < management_end_ip:
138 pecan.abort(
139 400,
140 _("management-start-ip not less than management-end-ip"))
141
142 if not len(IPRange(management_start_ip, management_end_ip)) >= \
143 MIN_MANAGEMENT_ADDRESSES:
144 pecan.abort(
145 400,
146 _("management address range must contain at least %d "
147 "addresses") % MIN_MANAGEMENT_ADDRESSES)
148
149 # Parse/validate the gateway
150 try:
151 validate_address_str(
152 management_gateway_ip_str, management_subnet)
153 except ValidateFail as e:
154 LOG.exception(e)
155 pecan.abort(400, _("management-gateway-ip invalid: %s") % e)
156
157 # Ensure subcloud management gateway is not within the actual subcloud
158 # management subnet address pool for consistency with the
159 # systemcontroller gateway restriction below. Address collision
160 # is not a concern as the address is added to sysinv.
161 subcloud_mgmt_address_start = IPAddress(management_start_ip_str)
162 subcloud_mgmt_address_end = IPAddress(management_end_ip_str)
163 subcloud_mgmt_gw_ip = IPAddress(management_gateway_ip_str)
164 if ((subcloud_mgmt_gw_ip >= subcloud_mgmt_address_start) and
165 (subcloud_mgmt_gw_ip <= subcloud_mgmt_address_end)):
166 pecan.abort(400, _("management-gateway-ip invalid, "
167 "is within management pool: %(start)s - "
168 "%(end)s") %
169 {'start': subcloud_mgmt_address_start,
170 'end': subcloud_mgmt_address_end})
171
172 # Ensure systemcontroller gateway is in the management subnet
173 # for the systemcontroller region.
174 management_address_pool = self._get_management_address_pool(context)
175 systemcontroller_subnet_str = "%s/%d" % (
176 management_address_pool.network,
177 management_address_pool.prefix)
178 systemcontroller_subnet = IPNetwork(systemcontroller_subnet_str)
179 try:
180 validate_address_str(
181 systemcontroller_gateway_ip_str, systemcontroller_subnet)
182 except ValidateFail as e:
183 LOG.exception(e)
184 pecan.abort(400, _("systemcontroller-gateway-ip invalid: %s") % e)
185 # Ensure systemcontroller gateway is not within the actual
186 # management subnet address pool to prevent address collision.
187 mgmt_address_start = IPAddress(management_address_pool.ranges[0][0])
188 mgmt_address_end = IPAddress(management_address_pool.ranges[0][1])
189 systemcontroller_gw_ip = IPAddress(systemcontroller_gateway_ip_str)
190 if ((systemcontroller_gw_ip >= mgmt_address_start) and
191 (systemcontroller_gw_ip <= mgmt_address_end)):
192 pecan.abort(400, _("systemcontroller-gateway-ip invalid, "
193 "is within management pool: %(start)s - "
194 "%(end)s") %
195 {'start': mgmt_address_start, 'end': mgmt_address_end})
196
197 def _create_subcloud_config_file(self, context, subcloud, payload):
198 """Creates the subcloud config file for a subcloud."""
199 DEFAULT_STR = '<EDIT>'
200
201 pxe_cidr = payload.get(
202 'pxe-subnet', DEFAULT_STR)
203 management_vlan = payload.get(
204 'management-vlan', DEFAULT_STR)
205 management_interface_mtu = payload.get(
206 'management-interface-mtu', DEFAULT_STR)
207 management_interface_ports = payload.get(
208 'management-interface-port', DEFAULT_STR)
209 oam_cidr = payload.get(
210 'oam-subnet', DEFAULT_STR)
211 oam_gateway = payload.get(
212 'oam-gateway-ip', DEFAULT_STR)
213 oam_ip_floating_address = payload.get(
214 'oam-floating-ip', DEFAULT_STR)
215 oam_ip_unit_0_address = payload.get(
216 'oam-unit-0-ip', DEFAULT_STR)
217 oam_ip_unit_1_address = payload.get(
218 'oam-unit-1-ip', DEFAULT_STR)
219 oam_interface_mtu = payload.get(
220 'oam-interface-mtu', DEFAULT_STR)
221 oam_interface_ports = payload.get(
222 'oam-interface-port', DEFAULT_STR)
223 system_mode = payload.get(
224 'system-mode', DEFAULT_STR)
225
226 management_address_pool = self._get_management_address_pool(context)
227 systemcontroller_subnet = "%s/%d" % (
228 management_address_pool.network,
229 management_address_pool.prefix)
230 sc_mgmt_floating_ip = management_address_pool.floating_address
231
232 subcloud_config = ""
233 if system_mode in [SYSTEM_MODE_SIMPLEX, SYSTEM_MODE_DUPLEX,
234 SYSTEM_MODE_DUPLEX_DIRECT]:
235 subcloud_config += (
236 "[SYSTEM]\n"
237 "SYSTEM_MODE={}\n".format(system_mode))
238
239 if system_mode == SYSTEM_MODE_SIMPLEX:
240 subcloud_oamip_config = (
241 "IP_ADDRESS = {oam_ip_floating_address}\n"
242 ).format(
243 oam_ip_floating_address=oam_ip_floating_address,
244 )
245 else:
246 subcloud_oamip_config = (
247 "IP_FLOATING_ADDRESS = {oam_ip_floating_address}\n"
248 "IP_UNIT_0_ADDRESS = {oam_ip_unit_0_address}\n"
249 "IP_UNIT_1_ADDRESS = {oam_ip_unit_1_address}\n"
250 ).format(
251 oam_ip_floating_address=oam_ip_floating_address,
252 oam_ip_unit_0_address=oam_ip_unit_0_address,
253 oam_ip_unit_1_address=oam_ip_unit_1_address,
254 )
255
256 MIN_MANAGEMENT_SUBNET_SIZE = 8
257 tmp_management_subnet = validate_network_str(
258 subcloud.management_subnet,
259 minimum_size=MIN_MANAGEMENT_SUBNET_SIZE)
260
261 is_ipv6_mgmt = (tmp_management_subnet.version == 6)
262
263 # If ipv6 then we need pxe subnet and management_vlan.
264 # If user specified pxe boot subnet, then management vlan is required
265 # and vice versa
266 if is_ipv6_mgmt or (pxe_cidr != DEFAULT_STR) or \
267 (management_vlan != DEFAULT_STR):
268 subcloud_config += (
269 "[REGION2_PXEBOOT_NETWORK]\n"
270 "PXEBOOT_CIDR = {pxe_cidr}\n"
271 "[MGMT_NETWORK]\n"
272 "VLAN = {management_vlan}\n"
273 ).format(
274 pxe_cidr=pxe_cidr,
275 management_vlan=management_vlan,
276 )
277 else:
278 subcloud_config += "[MGMT_NETWORK]\n"
279
280 subcloud_config += (
281 "CIDR = {management_cidr}\n"
282 "GATEWAY = {management_gateway}\n"
283 "IP_START_ADDRESS = {management_ip_start_address}\n"
284 "IP_END_ADDRESS = {management_ip_end_address}\n"
285 "DYNAMIC_ALLOCATION = Y\n"
286 "LOGICAL_INTERFACE = LOGICAL_INTERFACE_1\n"
287 "[LOGICAL_INTERFACE_1]\n"
288 "LAG_INTERFACE = N\n"
289 "INTERFACE_MTU = {management_interface_mtu}\n"
290 "INTERFACE_PORTS = {management_interface_ports}\n"
291 "[OAM_NETWORK]\n"
292 "CIDR = {oam_cidr}\n"
293 "GATEWAY = {oam_gateway}\n" +
294 subcloud_oamip_config +
295 "LOGICAL_INTERFACE = LOGICAL_INTERFACE_2\n"
296 "[LOGICAL_INTERFACE_2]\n"
297 "LAG_INTERFACE = N\n"
298 "INTERFACE_MTU = {oam_interface_mtu}\n"
299 "INTERFACE_PORTS = {oam_interface_ports}\n"
300 "[SHARED_SERVICES]\n"
301 "SYSTEM_CONTROLLER_SUBNET = {systemcontroller_subnet}\n"
302 "SYSTEM_CONTROLLER_FLOATING_ADDRESS = {sc_mgmt_floating_ip}\n"
303 "REGION_NAME = SystemController\n"
304 "ADMIN_PROJECT_NAME = admin\n"
305 "ADMIN_USER_NAME = admin\n"
306 "ADMIN_PASSWORD = {admin_password}\n"
307 "KEYSTONE_ADMINURL = {keystone_adminurl}\n"
308 "KEYSTONE_SERVICE_NAME = keystone\n"
309 "KEYSTONE_SERVICE_TYPE = identity\n"
310 "GLANCE_SERVICE_NAME = glance\n"
311 "GLANCE_SERVICE_TYPE = image\n"
312 "GLANCE_CACHED = True\n"
313 "[REGION_2_SERVICES]\n"
314 "REGION_NAME = {region_2_name}\n"
315 "[VERSION]\n"
316 "RELEASE = {release}\n"
317 ).format(
318 management_cidr=subcloud.management_subnet,
319 management_gateway=subcloud.management_gateway_ip,
320 management_ip_start_address=subcloud.management_start_ip,
321 management_ip_end_address=subcloud.management_end_ip,
322 management_interface_mtu=management_interface_mtu,
323 management_interface_ports=management_interface_ports,
324 oam_cidr=oam_cidr,
325 oam_gateway=oam_gateway,
326 oam_interface_mtu=oam_interface_mtu,
327 oam_interface_ports=oam_interface_ports,
328 systemcontroller_subnet=systemcontroller_subnet,
329 sc_mgmt_floating_ip=sc_mgmt_floating_ip,
330 admin_password=cfg.CONF.cache.admin_password,
331 keystone_adminurl=cfg.CONF.cache.auth_uri,
332 region_2_name=subcloud.name,
333 release=subcloud.software_version,
334 )
335 return subcloud_config
336
337 def _get_subcloud_users(self):
338 """Get the subcloud users and passwords from keyring"""
339 DEFAULT_SERVICE_PROJECT_NAME = 'services'
340 # First entry is openstack user name, second entry is the user stored
341 # in keyring. Not sure why heat_admin uses a different keystone name.
342 SUBCLOUD_USERS = [
343 ('nova', 'nova'),
344 ('placement', 'placement'),
345 ('sysinv', 'sysinv'),
346 ('patching', 'patching'),
347 ('heat', 'heat'),
348 ('ceilometer', 'ceilometer'),
349 ('vim', 'vim'),
350 ('aodh', 'aodh'),
351 ('panko', 'panko'),
352 ('mtce', 'mtce'),
353 ('cinder', 'cinder'),
354 ('glance', 'glance'),
355 ('neutron', 'neutron'),
356 ('heat_admin', 'heat-domain'),
357 ('gnocchi', 'gnocchi')
358 ]
359
360 user_list = list()
361 for user in SUBCLOUD_USERS:
362 password = keyring.get_password(user[1],
363 DEFAULT_SERVICE_PROJECT_NAME)
364 if password:
365 user_dict = dict()
366 user_dict['name'] = user[0]
367 user_dict['password'] = password
368 user_list.append(user_dict)
369 else:
370 LOG.error("User %s not found in keyring as %s" % (user[0],
371 user[1]))
372 pecan.abort(500, _('System configuration error'))
373
374 return user_list
375
376 def _get_management_address_pool(self, context):
377 """Get the system controller's management address pool"""
378 session = KeystoneClient().endpoint_cache.get_session_from_token(
379 context.auth_token, context.project)
380 sysinv_client = SysinvClient(consts.DEFAULT_REGION_NAME, session)
381 return sysinv_client.get_management_address_pool()
382
383 @index.when(method='GET', template='json')
384 def get(self, subcloud_ref=None, qualifier=None):
385 """Get details about subcloud.
386
387 :param subcloud_ref: ID or name of subcloud
388 """
389 context = restcomm.extract_context_from_environ()
390
391 if subcloud_ref is None:
392 # List of subclouds requested
393 subclouds = db_api.subcloud_get_all_with_status(context)
394 result = dict()
395 result['subclouds'] = []
396 first_time = True
397 subcloud_list = []
398 subcloud_status_list = []
399
400 # We get back a subcloud, subcloud_status pair for every
401 # subcloud_status entry corresponding to a subcloud. (Subcloud
402 # info repeats)
403 # Aggregate all the sync status for each of the
404 # endpoints per subcloud into an overall sync status
405 for subcloud, subcloud_status in subclouds:
406 subcloud_dict = db_api.subcloud_db_model_to_dict(subcloud)
407 subcloud_status_dict = db_api.subcloud_status_db_model_to_dict(
408 subcloud_status)
409 subcloud_dict.update(subcloud_status_dict)
410
411 if not first_time:
412 if subcloud_list[-1]['id'] == subcloud_dict['id']:
413 # We have a match for this subcloud id already,
414 # check if we have a same sync_status
415 if subcloud_list[-1][consts.SYNC_STATUS] != \
416 subcloud_dict[consts.SYNC_STATUS]:
417 subcloud_list[-1][consts.SYNC_STATUS] = \
418 consts.SYNC_STATUS_OUT_OF_SYNC
419
420 if subcloud_status:
421 subcloud_status_list.append(
422 db_api.subcloud_endpoint_status_db_model_to_dict( # noqa
423 subcloud_status))
424 subcloud_list[-1][
425 consts.ENDPOINT_SYNC_STATUS] = subcloud_status_list
426
427 else:
428 subcloud_status_list = []
429 if subcloud_status:
430 subcloud_status_list.append(
431 db_api.subcloud_endpoint_status_db_model_to_dict( # noqa
432 subcloud_status))
433
434 subcloud_list.append(subcloud_dict)
435 else:
436 if subcloud_status:
437 subcloud_status_list.append(
438 db_api.subcloud_endpoint_status_db_model_to_dict(
439 subcloud_status))
440 subcloud_list.append(subcloud_dict)
441
442 first_time = False
443
444 for s in subcloud_list:
445 result['subclouds'].append(s)
446
447 return result
448 else:
449 # Single subcloud requested
450 subcloud = None
451 subcloud_dict = dict()
452 subcloud_status_list = []
453 endpoint_sync_dict = dict()
454
455 if subcloud_ref.isdigit():
456 # Look up subcloud as an ID
457 try:
458 subcloud = db_api.subcloud_get(context, subcloud_ref)
459 except exceptions.SubcloudNotFound:
460 pecan.abort(404, _('Subcloud not found'))
461 else:
462 # Look up subcloud by name
463 try:
464 subcloud = db_api.subcloud_get_by_name(context,
465 subcloud_ref)
466 except exceptions.SubcloudNameNotFound:
467 pecan.abort(404, _('Subcloud not found'))
468
469 subcloud_id = subcloud.id
470
471 if qualifier:
472 # Configuration for this subcloud requested.
473 # Encrypt before sending.
474 if qualifier == 'config':
475 result = dict()
476 user_list = self._get_subcloud_users()
477
478 # Use a hash of the subcloud name + management subnet
479 # as the encryption key
480 hashstring = subcloud.name + subcloud.management_subnet
481 h = MD5.new()
482 h.update(hashstring)
483 encryption_key = h.hexdigest()
484 user_list_string = json.dumps(user_list)
485 user_list_encrypted = crypt.urlsafe_encrypt(
486 encryption_key,
487 user_list_string)
488 result['users'] = user_list_encrypted
489 return result
490 else:
491 pecan.abort(400, _('Invalid request'))
492 else:
493 # Data for this subcloud requested
494 # Build up and append a dictionary of the endpoints
495 # sync status to the result.
496 for subcloud, subcloud_status in db_api. \
497 subcloud_get_with_status(context, subcloud_id):
498 subcloud_dict = db_api.subcloud_db_model_to_dict(
499 subcloud)
500 # may be empty subcloud_status entry, account for this
501 if subcloud_status:
502 subcloud_status_list.append(
503 db_api.subcloud_endpoint_status_db_model_to_dict(
504 subcloud_status))
505 endpoint_sync_dict = {consts.ENDPOINT_SYNC_STATUS:
506 subcloud_status_list}
507 subcloud_dict.update(endpoint_sync_dict)
508
509 return subcloud_dict
510
511 @index.when(method='POST', template='json')
512 def post(self, subcloud_ref=None, qualifier=None):
513 """Create a new subcloud.
514
515 :param subcloud_ref: ID of or name subcloud (only used when generating
516 config)
517 :param qualifier: if 'config', returns the config INI file for the
518 subcloud
519 """
520
521 context = restcomm.extract_context_from_environ()
522
523 if subcloud_ref is None:
524 payload = eval(request.body)
525 if not payload:
526 pecan.abort(400, _('Body required'))
527 name = payload.get('name')
528 if not name:
529 pecan.abort(400, _('name required'))
530 management_subnet = payload.get('management-subnet')
531 if not management_subnet:
532 pecan.abort(400, _('management-subnet required'))
533 management_start_ip = payload.get('management-start-ip')
534 if not management_start_ip:
535 pecan.abort(400, _('management-start-ip required'))
536 management_end_ip = payload.get('management-end-ip')
537 if not management_end_ip:
538 pecan.abort(400, _('management-end-ip required'))
539 management_gateway_ip = payload.get('management-gateway-ip')
540 if not management_gateway_ip:
541 pecan.abort(400, _('management-gateway-ip required'))
542 systemcontroller_gateway_ip = \
543 payload.get('systemcontroller-gateway-ip')
544 if not systemcontroller_gateway_ip:
545 pecan.abort(400, _('systemcontroller-gateway-ip required'))
546
547 self._validate_subcloud_config(context,
548 name,
549 management_subnet,
550 management_start_ip,
551 management_end_ip,
552 management_gateway_ip,
553 systemcontroller_gateway_ip)
554
555 try:
556 # Ask dcmanager-manager to add the subcloud.
557 # It will do all the real work...
558 return self.rpc_client.add_subcloud(context, payload)
559 except RemoteError as e:
560 pecan.abort(422, e.value)
561 except Exception as e:
562 LOG.exception(e)
563 pecan.abort(500, _('Unable to create subcloud'))
564 elif qualifier:
565 if qualifier == 'config':
566 subcloud = None
567
568 if subcloud_ref.isdigit():
569 # Look up subcloud as an ID
570 try:
571 subcloud = db_api.subcloud_get(context, subcloud_ref)
572 except exceptions.SubcloudNotFound:
573 pecan.abort(404, _('Subcloud not found'))
574 else:
575 # Look up subcloud by name
576 try:
577 subcloud = db_api.subcloud_get_by_name(context,
578 subcloud_ref)
579 except exceptions.SubcloudNameNotFound:
580 pecan.abort(404, _('Subcloud not found'))
581
582 payload = dict()
583 if request.body:
584 payload = eval(request.body)
585 config_file = self._create_subcloud_config_file(
586 context, subcloud, payload)
587 result = dict()
588 result['config'] = config_file
589 return result
590 else:
591 pecan.abort(400, _('Invalid request'))
592 else:
593 pecan.abort(400, _('Invalid request'))
594
595 @index.when(method='PATCH', template='json')
596 def patch(self, subcloud_ref=None):
597 """Update a subcloud.
598
599 :param subcloud_ref: ID or name of subcloud to update
600 """
601
602 context = restcomm.extract_context_from_environ()
603 subcloud = None
604
605 if subcloud_ref is None:
606 pecan.abort(400, _('Subcloud ID required'))
607
608 payload = eval(request.body)
609 if not payload:
610 pecan.abort(400, _('Body required'))
611
612 if subcloud_ref.isdigit():
613 # Look up subcloud as an ID
614 try:
615 subcloud = db_api.subcloud_get(context, subcloud_ref)
616 except exceptions.SubcloudNotFound:
617 pecan.abort(404, _('Subcloud not found'))
618 else:
619 # Look up subcloud by name
620 try:
621 subcloud = db_api.subcloud_get_by_name(context,
622 subcloud_ref)
623 except exceptions.SubcloudNameNotFound:
624 pecan.abort(404, _('Subcloud not found'))
625
626 subcloud_id = subcloud.id
627
628 management_state = payload.get('management-state')
629 description = payload.get('description')
630 location = payload.get('location')
631
632 if not (management_state or description or location):
633 pecan.abort(400, _('nothing to update'))
634
635 # Syntax checking
636 if management_state and \
637 management_state not in [consts.MANAGEMENT_UNMANAGED,
638 consts.MANAGEMENT_MANAGED]:
639 pecan.abort(400, _('Invalid management-state'))
640
641 try:
642 # Inform dcmanager-manager that subcloud has been updated.
643 # It will do all the real work...
644 subcloud = self.rpc_client.update_subcloud(
645 context, subcloud_id, management_state=management_state,
646 description=description, location=location)
647 return subcloud
648 except RemoteError as e:
649 pecan.abort(422, e.value)
650 except Exception as e:
651 # additional exceptions.
652 LOG.exception(e)
653 pecan.abort(500, _('Unable to update subcloud'))
654
655 @index.when(method='delete', template='json')
656 def delete(self, subcloud_ref):
657 """Delete a subcloud.
658
659 :param subcloud_ref: ID or name of subcloud to delete.
660 """
661 context = restcomm.extract_context_from_environ()
662 subcloud = None
663
664 if subcloud_ref.isdigit():
665 # Look up subcloud as an ID
666 try:
667 subcloud = db_api.subcloud_get(context, subcloud_ref)
668 except exceptions.SubcloudNotFound:
669 pecan.abort(404, _('Subcloud not found'))
670 else:
671 # Look up subcloud by name
672 try:
673 subcloud = db_api.subcloud_get_by_name(context,
674 subcloud_ref)
675 except exceptions.SubcloudNameNotFound:
676 pecan.abort(404, _('Subcloud not found'))
677
678 subcloud_id = subcloud.id
679
680 try:
681 # Ask dcmanager-manager to delete the subcloud.
682 # It will do all the real work...
683 return self.rpc_client.delete_subcloud(context, subcloud_id)
684 except RemoteError as e:
685 pecan.abort(422, e.value)
686 except Exception as e:
687 LOG.exception(e)
688 pecan.abort(500, _('Unable to delete subcloud'))
diff --git a/dcmanager/api/controllers/v1/sw_update_options.py b/dcmanager/api/controllers/v1/sw_update_options.py
new file mode 100644
index 0000000..1b08366
--- /dev/null
+++ b/dcmanager/api/controllers/v1/sw_update_options.py
@@ -0,0 +1,244 @@
1# Copyright (c) 2017 Ericsson AB.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23from oslo_config import cfg
24from oslo_log import log as logging
25
26import pecan
27from pecan import expose
28from pecan import request
29
30from dcmanager.api.controllers import restcomm
31from dcmanager.common import consts
32from dcmanager.common import exceptions
33from dcmanager.common.i18n import _
34from dcmanager.common import utils
35from dcmanager.db import api as db_api
36from dcmanager.rpc import client as rpc_client
37
38CONF = cfg.CONF
39LOG = logging.getLogger(__name__)
40
41
42class SwUpdateOptionsController(object):
43
44 def __init__(self):
45 super(SwUpdateOptionsController, self).__init__()
46 self.rpc_client = rpc_client.ManagerClient()
47
48 @expose(generic=True, template='json')
49 def index(self):
50 # Route the request to specific methods with parameters
51 pass
52
53 @index.when(method='GET', template='json')
54 def get(self, subcloud_ref=None):
55 """Get details about software update options.
56
57 :param subcloud: name or id of subcloud (optional)
58 """
59 context = restcomm.extract_context_from_environ()
60
61 if subcloud_ref is None:
62 # List of all subcloud options requested.
63 # Prepend the all clouds default options to the result.
64
65 result = dict()
66 result['sw-update-options'] = list()
67
68 default_sw_update_opts_dict = utils.get_sw_update_opts(
69 context)
70
71 result['sw-update-options'].append(default_sw_update_opts_dict)
72
73 subclouds = db_api.sw_update_opts_get_all_plus_subcloud_info(
74 context)
75
76 for subcloud, sw_update_opts in subclouds:
77 if sw_update_opts:
78 result['sw-update-options'].append(
79 db_api.sw_update_opts_w_name_db_model_to_dict(
80 sw_update_opts, subcloud.name))
81
82 return result
83
84 elif subcloud_ref == consts.DEFAULT_REGION_NAME:
85 # Default options requested, guaranteed to succeed
86
87 return utils.get_sw_update_opts(context)
88
89 else:
90 # Specific subcloud options requested
91
92 if subcloud_ref.isdigit():
93 # Look up subcloud as an ID
94 try:
95 subcloud = db_api.subcloud_get(context, subcloud_ref)
96 except exceptions.SubcloudNotFound:
97 pecan.abort(404, _('Subcloud not found'))
98 else:
99 # Look up subcloud by name
100 try:
101 subcloud = db_api.subcloud_get_by_name(context,
102 subcloud_ref)
103 except exceptions.SubcloudNameNotFound:
104 pecan.abort(404, _('Subcloud not found'))
105
106 try:
107 return utils.get_sw_update_opts(
108 context, subcloud_id=subcloud.id)
109 except Exception as e:
110 pecan.abort(404, _('%s') % e)
111
112 @index.when(method='POST', template='json')
113 def post(self, subcloud_ref=None):
114 """Update or create sw update options.
115
116 :param subcloud: name or id of subcloud (optional)
117 """
118
119 # Note creating or updating subcloud specific options require
120 # setting all options.
121
122 context = restcomm.extract_context_from_environ()
123
124 payload = eval(request.body)
125 if not payload:
126 pecan.abort(400, _('Body required'))
127
128 if subcloud_ref == consts.DEFAULT_REGION_NAME:
129
130 # update default options
131 subcloud_name = consts.SW_UPDATE_DEFAULT_TITLE
132
133 if db_api.sw_update_opts_default_get(context):
134 # entry already in db, update it.
135 try:
136 sw_update_opts_ref = db_api.sw_update_opts_default_update(
137 context,
138 payload['storage-apply-type'],
139 payload['compute-apply-type'],
140 payload['max-parallel-computes'],
141 payload['alarm-restriction-type'],
142 payload['default-instance-action'])
143 except Exception as e:
144 LOG.exception(e)
145 raise e
146 else:
147 # no entry in db, create one.
148 try:
149 sw_update_opts_ref = db_api.sw_update_opts_default_create(
150 context,
151 payload['storage-apply-type'],
152 payload['compute-apply-type'],
153 payload['max-parallel-computes'],
154 payload['alarm-restriction-type'],
155 payload['default-instance-action'])
156 except Exception as e:
157 LOG.exception(e)
158 raise e
159 else:
160 # update subcloud options
161
162 if subcloud_ref.isdigit():
163 # Look up subcloud as an ID
164 try:
165 subcloud = db_api.subcloud_get(context, subcloud_ref)
166 except exceptions.SubcloudNotFound:
167 pecan.abort(404, _('Subcloud not found'))
168
169 subcloud_name = subcloud.name
170
171 else:
172 # Look up subcloud by name
173 try:
174 subcloud = db_api.subcloud_get_by_name(context,
175 subcloud_ref)
176 except exceptions.SubcloudNameNotFound:
177 pecan.abort(404, _('Subcloud not found'))
178
179 subcloud_name = subcloud_ref
180
181 sw_update_opts = db_api.sw_update_opts_get(context,
182 subcloud.id)
183
184 if sw_update_opts is None:
185 sw_update_opts_ref = db_api.sw_update_opts_create(
186 context,
187 subcloud.id,
188 payload['storage-apply-type'],
189 payload['compute-apply-type'],
190 payload['max-parallel-computes'],
191 payload['alarm-restriction-type'],
192 payload['default-instance-action'])
193
194 else:
195 # a row is present in table, update
196 sw_update_opts_ref = db_api.sw_update_opts_update(
197 context,
198 subcloud.id,
199 payload['storage-apply-type'],
200 payload['compute-apply-type'],
201 payload['max-parallel-computes'],
202 payload['alarm-restriction-type'],
203 payload['default-instance-action'])
204
205 return db_api.sw_update_opts_w_name_db_model_to_dict(
206 sw_update_opts_ref, subcloud_name)
207
208 @index.when(method='delete', template='json')
209 def delete(self, subcloud_ref):
210 """Delete the software update options."""
211
212 context = restcomm.extract_context_from_environ()
213
214 if subcloud_ref == consts.DEFAULT_REGION_NAME:
215 # Delete defaults.
216 # Note by deleting these, the next get will repopulate with
217 # the global constants.
218
219 try:
220 db_api.sw_update_opts_default_destroy(context)
221 except Exception:
222 return
223 else:
224
225 if subcloud_ref.isdigit():
226 # Look up subcloud as an ID
227 try:
228 subcloud = db_api.subcloud_get(context, subcloud_ref)
229 except exceptions.SubcloudNotFound:
230 pecan.abort(404, _('Subcloud not found'))
231
232 else:
233 # Look up subcloud by name
234 try:
235 subcloud = db_api.subcloud_get_by_name(context,
236 subcloud_ref)
237 except exceptions.SubcloudNameNotFound:
238 pecan.abort(404, _('Subcloud not found'))
239
240 # Delete the subcloud specific options
241 if db_api.sw_update_opts_get(context, subcloud.id):
242 db_api.sw_update_opts_destroy(context, subcloud.id)
243 else:
244 pecan.abort(404, _('Subcloud patch options not found'))
diff --git a/dcmanager/api/controllers/v1/sw_update_strategy.py b/dcmanager/api/controllers/v1/sw_update_strategy.py
new file mode 100755
index 0000000..2f76091
--- /dev/null
+++ b/dcmanager/api/controllers/v1/sw_update_strategy.py
@@ -0,0 +1,196 @@
1# Copyright (c) 2017 Ericsson AB.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23from oslo_config import cfg
24from oslo_log import log as logging
25from oslo_messaging import RemoteError
26
27import pecan
28from pecan import expose
29from pecan import request
30
31from dcmanager.api.controllers import restcomm
32from dcmanager.common import consts
33from dcmanager.common import exceptions
34from dcmanager.common.i18n import _
35from dcmanager.db import api as db_api
36from dcmanager.rpc import client as rpc_client
37
38CONF = cfg.CONF
39LOG = logging.getLogger(__name__)
40
41
42class SwUpdateStrategyController(object):
43
44 def __init__(self):
45 super(SwUpdateStrategyController, self).__init__()
46 self.rpc_client = rpc_client.ManagerClient()
47
48 @expose(generic=True, template='json')
49 def index(self):
50 # Route the request to specific methods with parameters
51 pass
52
53 @index.when(method='GET', template='json')
54 def get(self, steps=None, cloud_name=None):
55 """Get details about software update strategy.
56
57 :param steps: get the steps for this strategy (optional)
58 :param cloud_name: name of cloud (optional)
59 """
60 context = restcomm.extract_context_from_environ()
61
62 if steps is None:
63 # Strategy requested
64 strategy = None
65 try:
66 strategy = db_api.sw_update_strategy_get(context)
67 except exceptions.NotFound:
68 pecan.abort(404, _('Strategy not found'))
69
70 strategy_dict = db_api.sw_update_strategy_db_model_to_dict(
71 strategy)
72 return strategy_dict
73
74 elif steps == "steps":
75 # Steps for the strategy requested
76 if cloud_name is None:
77 # List of steps requested
78 result = dict()
79 result['strategy-steps'] = list()
80 strategy_steps = db_api.strategy_step_get_all(context)
81 for strategy_step in strategy_steps:
82 result['strategy-steps'].append(
83 db_api.strategy_step_db_model_to_dict(strategy_step))
84
85 return result
86 else:
87 # Single step requested
88 strategy_step = None
89 if cloud_name == consts.SYSTEM_CONTROLLER_NAME:
90 # The system controller step does not map to a subcloud,
91 # so has no name.
92 try:
93 strategy_step = db_api.strategy_step_get(context, None)
94 except exceptions.StrategyStepNotFound:
95 pecan.abort(404, _('Strategy step not found'))
96 else:
97 try:
98 strategy_step = db_api.strategy_step_get_by_name(
99 context, cloud_name)
100 except exceptions.StrategyStepNameNotFound:
101 pecan.abort(404, _('Strategy step not found'))
102
103 strategy_step_dict = db_api.strategy_step_db_model_to_dict(
104 strategy_step)
105 return strategy_step_dict
106
107 @index.when(method='POST', template='json')
108 def post(self, actions=None):
109 """Create a new software update strategy."""
110 context = restcomm.extract_context_from_environ()
111
112 payload = eval(request.body)
113 if not payload:
114 pecan.abort(400, _('Body required'))
115
116 if actions is None:
117 # Validate any options that were supplied
118 strategy_type = payload.get('type')
119 if not strategy_type:
120 pecan.abort(400, _('type required'))
121 if strategy_type not in consts.SW_UPDATE_TYPE_PATCH:
122 pecan.abort(400, _('type invalid'))
123
124 subcloud_apply_type = payload.get('subcloud-apply-type')
125 if subcloud_apply_type is not None:
126 if subcloud_apply_type not in [
127 consts.SUBCLOUD_APPLY_TYPE_PARALLEL,
128 consts.SUBCLOUD_APPLY_TYPE_SERIAL]:
129 pecan.abort(400, _('subcloud-apply-type invalid'))
130
131 max_parallel_subclouds_str = payload.get('max-parallel-subclouds')
132 if max_parallel_subclouds_str is not None:
133 max_parallel_subclouds = None
134 try:
135 max_parallel_subclouds = int(max_parallel_subclouds_str)
136 except ValueError:
137 pecan.abort(400, _('max-parallel-subclouds invalid'))
138 # TODO(Bart): Decide on a maximum
139 if max_parallel_subclouds < 1 or max_parallel_subclouds > 100:
140 pecan.abort(400, _('max-parallel-subclouds invalid'))
141
142 stop_on_failure = payload.get('stop-on-failure')
143 if stop_on_failure is not None:
144 if stop_on_failure not in ["true", "false"]:
145 pecan.abort(400, _('stop-on-failure invalid'))
146
147 try:
148 # Ask dcmanager-manager to create the strategy.
149 # It will do all the real work...
150 return self.rpc_client.create_sw_update_strategy(context,
151 payload)
152 except RemoteError as e:
153 pecan.abort(422, e.value)
154 except Exception as e:
155 LOG.exception(e)
156 pecan.abort(500, _('Unable to create strategy'))
157 elif actions == 'actions':
158 # Apply or abort a strategy
159 action = payload.get('action')
160 if not action:
161 pecan.abort(400, _('action required'))
162 if action == consts.SW_UPDATE_ACTION_APPLY:
163 try:
164 # Ask dcmanager-manager to apply the strategy.
165 # It will do all the real work...
166 return self.rpc_client.apply_sw_update_strategy(context)
167 except RemoteError as e:
168 pecan.abort(422, e.value)
169 except Exception as e:
170 LOG.exception(e)
171 pecan.abort(500, _('Unable to apply strategy'))
172 elif action == consts.SW_UPDATE_ACTION_ABORT:
173 try:
174 # Ask dcmanager-manager to abort the strategy.
175 # It will do all the real work...
176 return self.rpc_client.abort_sw_update_strategy(context)
177 except RemoteError as e:
178 pecan.abort(422, e.value)
179 except Exception as e:
180 LOG.exception(e)
181 pecan.abort(500, _('Unable to abort strategy'))
182
183 @index.when(method='delete', template='json')
184 def delete(self):
185 """Delete the software update strategy."""
186 context = restcomm.extract_context_from_environ()
187
188 try:
189 # Ask dcmanager-manager to delete the strategy.
190 # It will do all the real work...
191 return self.rpc_client.delete_sw_update_strategy(context)
192 except RemoteError as e:
193 pecan.abort(422, e.value)
194 except Exception as e:
195 LOG.exception(e)
196 pecan.abort(500, _('Unable to delete strategy'))
diff --git a/dcmanager/api/enforcer.py b/dcmanager/api/enforcer.py
new file mode 100644
index 0000000..14bab58
--- /dev/null
+++ b/dcmanager/api/enforcer.py
@@ -0,0 +1,78 @@
1# Copyright 2017 Ericsson AB.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15# Copyright (c) 2017 Wind River Systems, Inc.
16#
17# The right to copy, distribute, modify, or otherwise make use
18# of this software may be licensed only pursuant to the terms
19# of an applicable Wind River license agreement.
20#
21
22"""Policy enforcer for DC Manager."""
23
24from oslo_config import cfg
25from oslo_policy import policy
26
27from dcmanager.common import exceptions as exc
28
29
30_ENFORCER = None
31
32
33def enforce(action, context, target=None, do_raise=True,
34 exc=exc.NotAuthorized):
35 """Verify that the action is valid on the target in this context.
36
37 :param action: String, representing the action to be checked.
38 This should be colon separated for clarity.
39 i.e. ``sync:list``
40 :param context: DC Manager context.
41 :param target: Dictionary, representing the object of the action.
42 For object creation, this should be a dictionary
43 representing the location of the object.
44 e.g. ``{'project_id': context.project}``
45 :param do_raise: if True (the default), raises specified exception.
46 :param exc: Exception to be raised if not authorized. Default is
47 dcmanager.common.exceptions.NotAuthorized.
48
49 :return: returns True if authorized and False if not authorized and
50 do_raise is False.
51 """
52 if cfg.CONF.auth_strategy != 'keystone':
53 # Policy enforcement is supported now only with Keystone
54 # authentication.
55 return
56
57 target_obj = {
58 'project_id': context.project,
59 'user_id': context.user,
60 }
61
62 target_obj.update(target or {})
63 _ensure_enforcer_initialization()
64
65 try:
66 _ENFORCER.enforce(action, target_obj, context.to_dict(),
67 do_raise=do_raise, exc=exc)
68 return True
69
70 except Exception:
71 return False
72
73
74def _ensure_enforcer_initialization():
75 global _ENFORCER
76 if not _ENFORCER:
77 _ENFORCER = policy.Enforcer(cfg.CONF)
78 _ENFORCER.load_rules()
diff --git a/dcmanager/cmd/README.rst b/dcmanager/cmd/README.rst
new file mode 100755
index 0000000..169352f
--- /dev/null
+++ b/dcmanager/cmd/README.rst
@@ -0,0 +1,18 @@
1===============================
2cmd
3===============================
4
5Scripts to start the DC Manager API and Manager services
6
7api.py:
8 start API service
9 python api.py --config-file=/etc/dcmanager.conf
10
11manager.py:
12 start Manager service
13 python manager.py --config-file=/etc/dcmanager.conf
14
15manage.py:
16 CLI interface for dcmanager database management
17 dcmanager-manage --config-file /etc/dcmanager.conf db_sync
18 dcmanager-manage --config-file /etc/dcmanager.conf db_version
diff --git a/dcmanager/cmd/__init__.py b/dcmanager/cmd/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dcmanager/cmd/__init__.py
diff --git a/dcmanager/cmd/api.py b/dcmanager/cmd/api.py
new file mode 100644
index 0000000..2f3bba7
--- /dev/null
+++ b/dcmanager/cmd/api.py
@@ -0,0 +1,78 @@
1# Copyright 2015 Huawei Technologies Co., Ltd.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# Copyright (c) 2017 Wind River Systems, Inc.
17#
18# The right to copy, distribute, modify, or otherwise make use
19# of this software may be licensed only pursuant to the terms
20# of an applicable Wind River license agreement.
21#
22
23# Much of this module is based on the work of the Ironic team
24# see http://git.openstack.org/cgit/openstack/ironic/tree/ironic/cmd/api.py
25
26
27import sys
28
29import eventlet
30from oslo_config import cfg
31from oslo_log import log as logging
32from oslo_service import systemd
33from oslo_service import wsgi
34
35import logging as std_logging
36
37from dcmanager.api import api_config
38from dcmanager.api import app
39
40from dcmanager.common import config
41from dcmanager.common import messaging
42from dcorch.common import messaging as dcorch_messaging
43CONF = cfg.CONF
44config.register_options()
45LOG = logging.getLogger('dcmanager.api')
46eventlet.monkey_patch(os=False)
47
48
49def main():
50 api_config.init(sys.argv[1:])
51 api_config.setup_logging()
52 application = app.setup_app()
53
54 host = CONF.bind_host
55 port = CONF.bind_port
56 workers = CONF.api_workers
57
58 if workers < 1:
59 LOG.warning("Wrong worker number, worker = %(workers)s", workers)
60 workers = 1
61
62 LOG.info("Server on http://%(host)s:%(port)s with %(workers)s",
63 {'host': host, 'port': port, 'workers': workers})
64 messaging.setup()
65 dcorch_messaging.setup()
66 systemd.notify_once()
67 service = wsgi.Server(CONF, "DCManager", application, host, port)
68
69 app.serve(service, CONF, workers)
70
71 LOG.info("Configuration:")
72 CONF.log_opt_values(LOG, std_logging.INFO)
73
74 app.wait()
75
76
77if __name__ == '__main__':
78 main()
diff --git a/dcmanager/cmd/manage.py b/dcmanager/cmd/manage.py
new file mode 100644
index 0000000..cd0adad
--- /dev/null
+++ b/dcmanager/cmd/manage.py
@@ -0,0 +1,85 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12#
13# Copyright (c) 2017 Wind River Systems, Inc.
14#
15# The right to copy, distribute, modify, or otherwise make use
16# of this software may be licensed only pursuant to the terms
17# of an applicable Wind River license agreement.
18#
19
20"""
21CLI interface for DC Manager management.
22"""
23
24import sys
25
26from oslo_config import cfg
27from oslo_log import log as logging
28
29from dcmanager.common import config
30from dcmanager.db import api
31from dcmanager import version
32
33config.register_options()
34CONF = cfg.CONF
35
36
37def do_db_version():
38 '''Print database's current migration level.'''
39 print(api.db_version(api.get_engine()))
40
41
42def do_db_sync():
43 '''Place a database under migration control and upgrade.
44
45 DB is created first if necessary.
46 '''
47 api.db_sync(api.get_engine(), CONF.command.version)
48
49
50def add_command_parsers(subparsers):
51 parser = subparsers.add_parser('db_version')
52 parser.set_defaults(func=do_db_version)
53
54 parser = subparsers.add_parser('db_sync')
55 parser.set_defaults(func=do_db_sync)
56 parser.add_argument('version', nargs='?')
57 parser.add_argument('current_version', nargs='?')
58
59command_opt = cfg.SubCommandOpt('command',
60 title='Commands',
61 help='Show available commands.',
62 handler=add_command_parsers)
63
64
65def main():
66 logging.register_options(CONF)
67 logging.setup(CONF, 'dcmanager-manage')
68 CONF.register_cli_opt(command_opt)
69
70 try:
71 default_config_files = cfg.find_config_files('dcmanager',
72 'dcmanager-engine')
73 CONF(sys.argv[1:], project='dcmanager', prog='dcmanager-manage',
74 version=version.version_info.version_string(),
75 default_config_files=default_config_files)
76 except RuntimeError as e:
77 sys.exit("ERROR: %s" % e)
78
79 try:
80 CONF.command.func()
81 except Exception as e:
82 sys.exit("ERROR: %s" % e)
83
84if __name__ == '__main__':
85 main()
diff --git a/dcmanager/cmd/manager.py b/dcmanager/cmd/manager.py
new file mode 100644
index 0000000..ce474d1
--- /dev/null
+++ b/dcmanager/cmd/manager.py
@@ -0,0 +1,64 @@
1#!/usr/bin/env python
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14#
15# Copyright (c) 2017 Wind River Systems, Inc.
16#
17# The right to copy, distribute, modify, or otherwise make use
18# of this software may be licensed only pursuant to the terms
19# of an applicable Wind River license agreement.
20#
21
22"""
23DC Manager Engine Server.
24"""
25
26import eventlet
27eventlet.monkey_patch()
28
29from oslo_config import cfg
30from oslo_i18n import _lazy
31from oslo_log import log as logging
32from oslo_service import service
33
34from dcmanager.common import config
35from dcmanager.common import consts
36from dcmanager.common import messaging
37from dcorch.common import messaging as dcorch_messaging
38
39_lazy.enable_lazy()
40config.register_options()
41config.register_keystone_options()
42LOG = logging.getLogger('dcmanager.engine')
43
44
45def main():
46 logging.register_options(cfg.CONF)
47 cfg.CONF(project='dcmanager', prog='dcmanager-engine')
48 logging.setup(cfg.CONF, 'dcmanager-engine')
49 logging.set_defaults()
50 messaging.setup()
51 dcorch_messaging.setup()
52
53 from dcmanager.manager import service as manager
54
55 srv = manager.DCManagerService(cfg.CONF.host,
56 consts.TOPIC_DC_MANAGER)
57 launcher = service.launch(cfg.CONF,
58 srv, workers=cfg.CONF.workers)
59 # the following periodic tasks are intended serve as HA checking
60 # srv.create_periodic_tasks()
61 launcher.wait()
62
63if __name__ == '__main__':
64 main()
diff --git a/dcmanager/common/__init__.py b/dcmanager/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dcmanager/common/__init__.py
diff --git a/dcmanager/common/config.py b/dcmanager/common/config.py
new file mode 100644
index 0000000..4acf4fb
--- /dev/null
+++ b/dcmanager/common/config.py
@@ -0,0 +1,159 @@
1# Copyright 2016 Ericsson AB
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11# License for the specific language governing permissions and limitations
12# under the License.
13#
14# Copyright (c) 2017 Wind River Systems, Inc.
15#
16# The right to copy, distribute, modify, or otherwise make use
17# of this software may be licensed only pursuant to the terms
18# of an applicable Wind River license agreement.
19#
20
21"""
22File to store all the configurations
23"""
24from oslo_config import cfg
25from oslo_utils import importutils
26
27# Ensure keystonemiddleware options are imported
28importutils.import_module('keystonemiddleware.auth_token')
29
30global_opts = [
31 cfg.BoolOpt('use_default_quota_class',
32 default=True,
33 help='Enables or disables use of default quota class '
34 'with default quota.'),
35 cfg.IntOpt('report_interval',
36 default=60,
37 help='Seconds between running periodic reporting tasks.'),
38]
39
40# OpenStack credentials used for Endpoint Cache
41# We need to register the below non-standard config
42# options to dcmanager engine
43keystone_opts = [
44 cfg.StrOpt('username',
45 help='Username of account'),
46 cfg.StrOpt('password',
47 help='Password of account'),
48 cfg.StrOpt('project_name',
49 help='Tenant name of account'),
50 cfg.StrOpt('user_domain_name',
51 default='Default',
52 help='User domain name of account'),
53 cfg.StrOpt('project_domain_name',
54 default='Default',
55 help='Project domain name of account'),
56]
57
58
59# Pecan_opts
60pecan_opts = [
61 cfg.StrOpt(
62 'root',
63 default='dcmanager.api.controllers.root.RootController',
64 help='Pecan root controller'
65 ),
66 cfg.ListOpt(
67 'modules',
68 default=["dcmanager.api"],
69 help='A list of modules where pecan will search for applications.'
70 ),
71 cfg.BoolOpt(
72 'debug',
73 default=False,
74 help='Enables the ability to display tracebacks in the browser and'
75 'interactively debug during development.'
76 ),
77 cfg.BoolOpt(
78 'auth_enable',
79 default=True,
80 help='Enables user authentication in pecan.'
81 )
82]
83
84
85# OpenStack credentials used for Endpoint Cache
86cache_opts = [
87 cfg.StrOpt('auth_uri',
88 help='Keystone authorization url'),
89 cfg.StrOpt('identity_uri',
90 help='Keystone service url'),
91 cfg.StrOpt('admin_username',
92 help='Username of admin account, needed when'
93 ' auto_refresh_endpoint set to True'),
94 cfg.StrOpt('admin_password',
95 help='Password of admin account, needed when'
96 ' auto_refresh_endpoint set to True'),
97 cfg.StrOpt('admin_tenant',
98 help='Tenant name of admin account, needed when'
99 ' auto_refresh_endpoint set to True'),
100 cfg.StrOpt('admin_user_domain_name',
101 default='Default',
102 help='User domain name of admin account, needed when'
103 ' auto_refresh_endpoint set to True'),
104 cfg.StrOpt('admin_project_domain_name',
105 default='Default',
106 help='Project domain name of admin account, needed when'
107 ' auto_refresh_endpoint set to True')
108]
109
110scheduler_opts = [
111 cfg.BoolOpt('periodic_enable',
112 default=True,
113 help='boolean value for enable/disable periodic tasks'),
114 cfg.IntOpt('subcloud_audit_interval',
115 default=180,
116 help='periodic time interval for subcloud audit'),
117 cfg.IntOpt('patch_audit_interval',
118 default=10,
119 help='periodic time interval for patch audit')
120]
121
122common_opts = [
123 cfg.IntOpt('workers', default=1,
124 help='number of workers'),
125 cfg.StrOpt('host',
126 default='localhost',
127 help='hostname of the machine')
128]
129
130scheduler_opt_group = cfg.OptGroup(name='scheduler',
131 title='Scheduler options for periodic job')
132keystone_opt_group = cfg.OptGroup(name='keystone_authtoken',
133 title='Keystone options')
134# The group stores the pecan configurations.
135pecan_group = cfg.OptGroup(name='pecan',
136 title='Pecan options')
137
138cache_opt_group = cfg.OptGroup(name='cache',
139 title='OpenStack Credentials')
140
141
142def list_opts():
143 yield cache_opt_group.name, cache_opts
144 yield scheduler_opt_group.name, scheduler_opts
145 yield pecan_group.name, pecan_opts
146 yield None, global_opts
147 yield None, common_opts
148
149
150def register_options():
151 for group, opts in list_opts():
152 cfg.CONF.register_opts(opts, group=group)
153
154
155# Only necessary for dcmanager engine, keystone_authtoken options for
156# dcmanager-api will get picked up and registered automatically from the
157# config file
158def register_keystone_options():
159 cfg.CONF.register_opts(keystone_opts, group=keystone_opt_group.name)
diff --git a/dcmanager/common/consts.py b/dcmanager/common/consts.py
new file mode 100644
index 0000000..7e63ef9
--- /dev/null
+++ b/dcmanager/common/consts.py
@@ -0,0 +1,90 @@
1# Copyright (c) 2016 Ericsson AB.
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14#
15# Copyright (c) 2017 Wind River Systems, Inc.
16#
17# The right to copy, distribute, modify, or otherwise make use
18# of this software may be licensed only pursuant to the terms
19# of an applicable Wind River license agreement.
20#
21
22RPC_API_VERSION = "1.0"
23
24TOPIC_DC_MANAGER = "dcmanager"
25
26PATCH_VAULT_DIR = "/opt/patch-vault"
27
28# Well known region names
29SYSTEM_CONTROLLER_NAME = "SystemController"
30DEFAULT_REGION_NAME = "RegionOne"
31
32# Subcloud management state
33MANAGEMENT_UNMANAGED = "unmanaged"
34MANAGEMENT_MANAGED = "managed"
35
36# Subcloud availability status
37AVAILABILITY_OFFLINE = "offline"
38AVAILABILITY_ONLINE = "online"
39
40# Subcloud sync status
41SYNC_STATUS_UNKNOWN = "unknown"
42SYNC_STATUS_IN_SYNC = "in-sync"
43SYNC_STATUS_OUT_OF_SYNC = "out-of-sync"
44
45# Subcloud endpoint related database fields
46ENDPOINT_SYNC_STATUS = "endpoint_sync_status"
47SYNC_STATUS = "sync_status"
48ENDPOINT_TYPE = "endpoint_type"
49
50# Service group status
51SERVICE_GROUP_STATUS_ACTIVE = "active"
52
53# Availability fail count
54AVAIL_FAIL_COUNT_TO_ALARM = 2
55AVAIL_FAIL_COUNT_MAX = 9999
56
57# Software update type
58SW_UPDATE_TYPE_PATCH = "patch"
59SW_UPDATE_TYPE_UPGRADE = "upgrade"
60
61# Software update states
62SW_UPDATE_STATE_INITIAL = "initial"
63SW_UPDATE_STATE_APPLYING = "applying"
64SW_UPDATE_STATE_ABORT_REQUESTED = "abort requested"
65SW_UPDATE_STATE_ABORTING = "aborting"
66SW_UPDATE_STATE_COMPLETE = "complete"
67SW_UPDATE_STATE_ABORTED = "aborted"
68SW_UPDATE_STATE_FAILED = "failed"
69SW_UPDATE_STATE_DELETING = "deleting"
70SW_UPDATE_STATE_DELETED = "deleted"
71
72# Software update actions
73SW_UPDATE_ACTION_APPLY = "apply"
74SW_UPDATE_ACTION_ABORT = "abort"
75
76# Subcloud apply types
77SUBCLOUD_APPLY_TYPE_PARALLEL = "parallel"
78SUBCLOUD_APPLY_TYPE_SERIAL = "serial"
79
80# Strategy step states
81STRATEGY_STATE_INITIAL = "initial"
82STRATEGY_STATE_UPDATING_PATCHES = "updating patches"
83STRATEGY_STATE_CREATING_STRATEGY = "creating strategy"
84STRATEGY_STATE_APPLYING_STRATEGY = "applying strategy"
85STRATEGY_STATE_FINISHING = "finishing"
86STRATEGY_STATE_COMPLETE = "complete"
87STRATEGY_STATE_ABORTED = "aborted"
88STRATEGY_STATE_FAILED = "failed"
89
90SW_UPDATE_DEFAULT_TITLE = "all clouds default"
diff --git a/dcmanager/common/context.py b/dcmanager/common/context.py
new file mode 100644
index 0000000..40abec1
--- /dev/null
+++ b/dcmanager/common/context.py
@@ -0,0 +1,154 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12#
13# Copyright (c) 2017 Wind River Systems, Inc.
14#
15# The right to copy, distribute, modify, or otherwise make use
16# of this software may be licensed only pursuant to the terms
17# of an applicable Wind River license agreement.
18#
19
20import pecan
21from pecan import hooks
22
23from oslo_context import context as base_context
24from oslo_utils import encodeutils
25
26from dcmanager.common import policy
27from dcmanager.db import api as db_api
28
29ALLOWED_WITHOUT_AUTH = '/'
30
31
32class RequestContext(base_context.RequestContext):
33 '''Stores information about the security context.
34
35 The context encapsulates information related to the user accessing the
36 the system, as well as additional request information.
37 '''
38
39 def __init__(self, auth_token=None, user=None, project=None,
40 domain=None, user_domain=None, project_domain=None,
41 is_admin=None, read_only=False, show_deleted=False,
42 request_id=None, auth_url=None, trusts=None,
43 user_name=None, project_name=None, domain_name=None,
44 user_domain_name=None, project_domain_name=None,
45 auth_token_info=None, region_name=None, roles=None,
46 password=None, **kwargs):
47
48 '''Initializer of request context.'''
49 # We still have 'tenant' param because oslo_context still use it.
50 super(RequestContext, self).__init__(
51 auth_token=auth_token, user=user, tenant=project,
52 domain=domain, user_domain=user_domain,
53 project_domain=project_domain, roles=roles,
54 read_only=read_only, show_deleted=show_deleted,
55 request_id=request_id)
56
57 # request_id might be a byte array
58 self.request_id = encodeutils.safe_decode(self.request_id)
59
60 # we save an additional 'project' internally for use
61 self.project = project
62
63 # Session for DB access
64 self._session = None
65
66 self.auth_url = auth_url
67 self.trusts = trusts
68
69 self.user_name = user_name
70 self.project_name = project_name
71 self.domain_name = domain_name
72 self.user_domain_name = user_domain_name
73 self.project_domain_name = project_domain_name
74
75 self.auth_token_info = auth_token_info
76 self.region_name = region_name
77 self.roles = roles or []
78 self.password = password
79
80 # Check user is admin or not
81 if is_admin is None:
82 self.is_admin = policy.enforce(self, 'context_is_admin',
83 target={'project': self.project},
84 do_raise=False)
85 else:
86 self.is_admin = is_admin
87
88 @property
89 def session(self):
90 if self._session is None:
91 self._session = db_api.get_session()
92 return self._session
93
94 def to_dict(self):
95 return {
96 'auth_url': self.auth_url,
97 'auth_token': self.auth_token,
98 'auth_token_info': self.auth_token_info,
99 'user': self.user,
100 'user_name': self.user_name,
101 'user_domain': self.user_domain,
102 'user_domain_name': self.user_domain_name,
103 'project': self.project,
104 'project_name': self.project_name,
105 'project_domain': self.project_domain,
106 'project_domain_name': self.project_domain_name,
107 'domain': self.domain,
108 'domain_name': self.domain_name,
109 'trusts': self.trusts,
110 'region_name': self.region_name,
111 'roles': self.roles,
112 'show_deleted': self.show_deleted,
113 'is_admin': self.is_admin,
114 'request_id': self.request_id,
115 'password': self.password,
116 }
117
118 @classmethod
119 def from_dict(cls, values):
120 return cls(**values)
121
122
123def get_admin_context(show_deleted=False):
124 return RequestContext(is_admin=True, show_deleted=show_deleted)
125
126
127def get_service_context(**args):
128 '''An abstraction layer for getting service context.
129
130 There could be multiple cloud backends for dcmanager to use. This
131 abstraction layer provides an indirection for dcmanager to get the
132 credentials of 'dcmanager' user on the specific cloud. By default,
133 this credential refers to the credentials built for dcmanager middleware
134 in an OpenStack cloud.
135 '''
136 pass
137
138
139class AuthHook(hooks.PecanHook):
140 def before(self, state):
141 if state.request.path == ALLOWED_WITHOUT_AUTH:
142 return
143 req = state.request
144 identity_status = req.headers.get('X-Identity-Status')
145 service_identity_status = req.headers.get('X-Service-Identity-Status')
146 if (identity_status == 'Confirmed' or
147 service_identity_status == 'Confirmed'):
148 return
149 if req.headers.get('X-Auth-Token'):
150 msg = 'Auth token is invalid: %s' % req.headers['X-Auth-Token']
151 else:
152 msg = 'Authentication required'
153 msg = "Failed to validate access token: %s" % str(msg)
154 pecan.abort(status_code=401, detail=msg)
diff --git a/dcmanager/common/exceptions.py b/dcmanager/common/exceptions.py
new file mode 100644
index 0000000..a9bfc0a
--- /dev/null
+++ b/dcmanager/common/exceptions.py
@@ -0,0 +1,148 @@
1# Copyright 2015 Huawei Technologies Co., Ltd.
2# Copyright 2015 Ericsson AB.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16#
17# Copyright (c) 2017 Wind River Systems, Inc.
18#
19# The right to copy, distribute, modify, or otherwise make use
20# of this software may be licensed only pursuant to the terms
21# of an applicable Wind River license agreement.
22#
23
24"""
25DC Manager base exception handling.
26"""
27import six
28
29from oslo_utils import excutils
30
31from dcmanager.common.i18n import _
32
33
34class DCManagerException(Exception):
35 """Base DC Manager Exception.
36
37 To correctly use this class, inherit from it and define
38 a 'message' property. That message will get printf'd
39 with the keyword arguments provided to the constructor.
40 """
41
42 message = _("An unknown exception occurred.")
43
44 def __init__(self, **kwargs):
45 try:
46 super(DCManagerException, self).__init__(self.message % kwargs)
47 self.msg = self.message % kwargs
48 except Exception:
49 with excutils.save_and_reraise_exception() as ctxt:
50 if not self.use_fatal_exceptions():
51 ctxt.reraise = False
52 # at least get the core message out if something happened
53 super(DCManagerException, self).__init__(self.message)
54
55 if six.PY2:
56 def __unicode__(self):
57 return unicode(self.msg)
58
59 def use_fatal_exceptions(self):
60 return False
61
62
63class BadRequest(DCManagerException):
64 message = _('Bad %(resource)s request: %(msg)s')
65
66
67class NotFound(DCManagerException):
68 message = _("Not found")
69
70
71class Conflict(DCManagerException):
72 message = _('Conflict: %(msg)s')
73
74
75class NotAuthorized(DCManagerException):
76 message = _("Not authorized.")
77
78
79class ServiceUnavailable(DCManagerException):
80 message = _("The service is unavailable")
81
82
83class AdminRequired(NotAuthorized):
84 message = _("User does not have admin privileges: %(reason)s")
85
86
87class InUse(DCManagerException):
88 message = _("The resource is inuse")
89
90
91class InvalidConfigurationOption(DCManagerException):
92 message = _("An invalid value was provided for %(opt_name)s: "
93 "%(opt_value)s")
94
95
96class SubcloudNotFound(NotFound):
97 message = _("Subcloud with id %(subcloud_id)s doesn't exist.")
98
99
100class SubcloudNameNotFound(NotFound):
101 message = _("Subcloud with name %(name)s doesn't exist.")
102
103
104class SubcloudNotOnline(DCManagerException):
105 message = _("Subcloud is not online.")
106
107
108class SubcloudStatusNotFound(NotFound):
109 message = _("SubcloudStatus with subcloud_id %(subcloud_id)s and "
110 "endpoint_type %(endpoint_type)s doesn't exist.")
111
112
113class SubcloudNotUnmanaged(DCManagerException):
114 message = _("Subcloud must be unmanaged to perform this operation.")
115
116
117class SubcloudNotOffline(DCManagerException):
118 message = _("Subcloud must be powered down to perform this operation.")
119
120
121class SubcloudPatchOptsNotFound(NotFound):
122 message = _("No options found for Subcloud with id %(subcloud_id)s, "
123 "defaults will be used.")
124
125
126class ConnectionRefused(DCManagerException):
127 message = _("Connection to the service endpoint is refused")
128
129
130class TimeOut(DCManagerException):
131 message = _("Timeout when connecting to OpenStack Service")
132
133
134class InternalError(DCManagerException):
135 message = _("Error when performing operation")
136
137
138class InvalidInputError(DCManagerException):
139 message = _("An invalid value was provided")
140
141
142class StrategyStepNotFound(NotFound):
143 message = _("StrategyStep with subcloud_id %(subcloud_id)s "
144 "doesn't exist.")
145
146
147class StrategyStepNameNotFound(NotFound):
148 message = _("StrategyStep with name %(name)s doesn't exist.")
diff --git a/dcmanager/common/i18n.py b/dcmanager/common/i18n.py
new file mode 100644
index 0000000..e883218
--- /dev/null
+++ b/dcmanager/common/i18n.py
@@ -0,0 +1,27 @@
1# All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14#
15# Copyright (c) 2017 Wind River Systems, Inc.
16#
17# The right to copy, distribute, modify, or otherwise make use
18# of this software may be licensed only pursuant to the terms
19# of an applicable Wind River license agreement.
20#
21
22import oslo_i18n
23
24_translators = oslo_i18n.TranslatorFactory(domain='dcmanager')
25
26# The primary translation function using the well-known name "_"
27_ = _translators.primary
diff --git a/dcmanager/common/manager.py b/dcmanager/common/manager.py
new file mode 100644
index 0000000..c7b0460
--- /dev/null
+++ b/dcmanager/common/manager.py
@@ -0,0 +1,124 @@
1# Copyright 2010 United States Government as represented by the
2# Administrator of the National Aeronautics and Space Administration.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16# copy and modify from Nova manager.py
17#
18# Copyright (c) 2017 Wind River Systems, Inc.
19#
20# The right to copy, distribute, modify, or otherwise make use
21# of this software may be licensed only pursuant to the terms
22# of an applicable Wind River license agreement.
23#
24
25"""Base Manager class.
26Managers are responsible for a certain aspect of the system. It is a logical
27grouping of code relating to a portion of the system. In general other
28components should be using the manager to make changes to the components that
29it is responsible for.
30For example, other components that need to deal with volumes in some way,
31should do so by calling methods on the VolumeManager instead of directly
32changing fields in the database. This allows us to keep all of the code
33relating to volumes in the same place.
34We have adopted a basic strategy of Smart managers and dumb data, which means
35rather than attaching methods to data objects, components should call manager
36methods that act on the data.
37Methods on managers that can be executed locally should be called directly. If
38a particular method must execute on a remote host, this should be done via rpc
39to the service that wraps the manager
40Managers should be responsible for most of the db access, and
41non-implementation specific data. Anything implementation specific that can't
42be generalized should be done by the Driver.
43Managers will often provide methods for initial setup of a host or periodic
44tasks to a wrapping service.
45This module provides Manager, a base class for managers.
46"""
47
48from oslo_config import cfg
49from oslo_log import log as logging
50from oslo_service import periodic_task
51
52from dcmanager.common import config
53
54CONF = cfg.CONF
55config.register_options()
56LOG = logging.getLogger(__name__)
57
58
59class PeriodicTasks(periodic_task.PeriodicTasks):
60 def __init__(self):
61 super(PeriodicTasks, self).__init__(CONF)
62
63
64class Manager(PeriodicTasks):
65
66 def __init__(self, host=None, service_name='undefined'):
67 if not host:
68 host = cfg.CONF.host
69 self.host = host
70 self.service_name = service_name
71 # self.notifier = rpc.get_notifier(self.service_name, self.host)
72 self.additional_endpoints = []
73 super(Manager, self).__init__()
74
75 def periodic_tasks(self, context, raise_on_error=False):
76 """Tasks to be run at a periodic interval."""
77 return self.run_periodic_tasks(context, raise_on_error=raise_on_error)
78
79 def init_host(self):
80
81 """init_host
82
83 Hook to do additional manager initialization when one requests
84 the service be started. This is called before any service record
85 is created.
86 Child classes should override this method.
87 """
88
89 pass
90
91 def cleanup_host(self):
92
93 """cleanup_host
94
95 Hook to do cleanup work when the service shuts down.
96 Child classes should override this method.
97 """
98
99 pass
100
101 def pre_start_hook(self):
102
103 """pre_start_hook
104
105 Hook to provide the manager the ability to do additional
106 start-up work before any RPC queues/consumers are created. This is
107 called after other initialization has succeeded and a service
108 record is created.
109 Child classes should override this method.
110 """
111
112 pass
113
114 def post_start_hook(self):
115
116 """post_start_hook
117
118 Hook to provide the manager the ability to do additional
119 start-up work immediately after a service creates RPC consumers
120 and starts 'running'.
121 Child classes should override this method.
122 """
123
124 pass
diff --git a/dcmanager/common/messaging.py b/dcmanager/common/messaging.py
new file mode 100644
index 0000000..badc963
--- /dev/null
+++ b/dcmanager/common/messaging.py
@@ -0,0 +1,118 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12#
13# Copyright (c) 2017 Wind River Systems, Inc.
14#
15# The right to copy, distribute, modify, or otherwise make use
16# of this software may be licensed only pursuant to the terms
17# of an applicable Wind River license agreement.
18#
19
20import eventlet
21
22from oslo_config import cfg
23import oslo_messaging
24from oslo_serialization import jsonutils
25
26from dcmanager.common import context
27
28TRANSPORT = None
29NOTIFIER = None
30
31_ALIASES = {
32 'dcmanager.openstack.common.rpc.impl_kombu': 'rabbit',
33 'dcmanager.openstack.common.rpc.impl_qpid': 'qpid',
34 'dcmanager.openst