From bb2d0e5a84e0655157cc17139b2557f66f9d0ea1 Mon Sep 17 00:00:00 2001 From: Stan Lagun Date: Thu, 4 Aug 2016 10:14:11 -0700 Subject: [PATCH] Support for multi-regional apps was added Now all OpenStack resource classes inherit CloudResource that provides getRegion method and regionName property. This allows to assign resources to different regions. getRegion() returns CloudRegion instance that resource or it parent belong to. CloudRegion has the similar interface to Environment class and is the correct way to get HeatStack instance associated with the regoin, default network configuration, security group manager and agent listener instances. Environment acts as the default region so backward compatibility is not broken. However new applications should not use environment to set security group rules but rather a region(s) of their instance(s) in order to work correctly when their instances were configured to use region other then the default. Change-Id: I4dbf40c65042e9a354f3bfadfcd63a63e6e3e418 --- meta/io.murano/Classes/CloudRegion.yaml | 55 +++++++++++++ meta/io.murano/Classes/CloudResource.yaml | 29 +++++++ meta/io.murano/Classes/Environment.yaml | 80 ++++++++++++------- meta/io.murano/Classes/SharedIp.yaml | 33 ++++---- .../Classes/resources/CinderVolume.yaml | 15 ++-- .../Classes/resources/ConfLangInstance.yaml | 13 ++- .../resources/ExistingNeutronNetwork.yaml | 2 +- .../resources/HeatSWConfigInstance.yaml | 11 ++- .../io.murano/Classes/resources/Instance.yaml | 66 ++++++++------- .../Classes/resources/LinuxInstance.yaml | 4 +- .../resources/LinuxMuranoInstance.yaml | 21 +++-- meta/io.murano/Classes/resources/Network.yaml | 4 +- .../Classes/resources/NeutronNetwork.yaml | 32 ++++---- .../Classes/resources/NeutronNetworkBase.yaml | 15 ++-- .../Classes/resources/NovaNetwork.yaml | 5 +- meta/io.murano/Classes/resources/Volume.yaml | 2 + .../system/AwsSecurityGroupManager.yaml | 13 ++- .../system/NeutronSecurityGroupManager.yaml | 14 +++- .../Classes/system/SecurityGroupManager.yaml | 5 +- meta/io.murano/Classes/test/TestFixture.yaml | 5 +- meta/io.murano/manifest.yaml | 4 +- murano/dsl/dsl.py | 5 +- murano/dsl/helpers.py | 2 +- murano/engine/system/agent.py | 14 ++-- murano/engine/system/agent_listener.py | 6 +- murano/engine/system/common.py | 8 +- murano/engine/system/heat_stack.py | 9 ++- murano/engine/system/net_explorer.py | 4 +- murano/tests/unit/dsl/meta/AgentTests.yaml | 16 ---- murano/tests/unit/dsl/test_agent.py | 30 ++----- .../multi-regional-apps-b64afbaeafd5b9c5.yaml | 14 ++++ 31 files changed, 316 insertions(+), 220 deletions(-) create mode 100644 meta/io.murano/Classes/CloudRegion.yaml create mode 100644 meta/io.murano/Classes/CloudResource.yaml delete mode 100644 murano/tests/unit/dsl/meta/AgentTests.yaml create mode 100644 releasenotes/notes/multi-regional-apps-b64afbaeafd5b9c5.yaml diff --git a/meta/io.murano/Classes/CloudRegion.yaml b/meta/io.murano/Classes/CloudRegion.yaml new file mode 100644 index 00000000..babc4102 --- /dev/null +++ b/meta/io.murano/Classes/CloudRegion.yaml @@ -0,0 +1,55 @@ +Namespaces: + res: io.murano.resources + sys: io.murano.system + =: io.murano + +Name: CloudRegion + +Properties: + name: + Contract: $.string() + + agentListener: + Contract: $.class(sys:AgentListener) + Usage: Runtime + + stack: + Contract: $.class(sys:HeatStack) + Usage: Runtime + + defaultNetworks: + Contract: + environment: $.class(res:Network) + flat: $.class(res:Network) + + securityGroupManager: + Contract: $.class(sys:SecurityGroupManager) + Usage: Runtime + +Methods: + getConfig: + Body: + - Return: $._environment.regionConfigs.get( + $.name, $._environment.regionConfigs.get('')) + + .init: + Body: + - $._environment: $.find(Environment).require() + - $generatedStackName: $.getAttr(generatedStackName) + - If: $generatedStackName = null + Then: + - $generatedStackName: list($.name, randomName()).join('-') + - $.setAttr(generatedStackName, $generatedStackName) + - $this.agentListener: new(sys:AgentListener, $this, name => $generatedStackName) + - $stackDescriptionFormat: 'This stack was generated by Murano for environment {0} (ID: {1}) - region {2}' + - $this.stack: new(sys:HeatStack, $this, + name => 'murano-' + $generatedStackName, + description => $stackDescriptionFormat.format($._environment.name, id($._environment), $.name)) + + - $this.securityGroupManager: + coalesce($.defaultNetworks.environment, $.defaultNetworks.flat)?. + generateSecurityGroupManager() + + .destroy: + Body: + - $.stack.delete() diff --git a/meta/io.murano/Classes/CloudResource.yaml b/meta/io.murano/Classes/CloudResource.yaml new file mode 100644 index 00000000..5bcbaae5 --- /dev/null +++ b/meta/io.murano/Classes/CloudResource.yaml @@ -0,0 +1,29 @@ +Namespaces: + =: io.murano + +Name: CloudResource + +Properties: + regionName: + Contract: $.string() + +Methods: + .init: + Body: + $._region: null + + getRegion: + Meta: + 'io.murano.metadata.engine.Synchronize': + onThis: false + Body: + - If: $._region = null + Then: + - $env: $.find(Environment).require() + - $regionName: generate($this, $ != null, $.find(CloudResource)). + select($.regionName).where($ != null).first($env.region) + - $._region: $.find(CloudRegion) + - If: $._region = null or $._region.name != $regionName + Then: + $._region: $env.regions[$regionName] + - Return: $._region diff --git a/meta/io.murano/Classes/Environment.yaml b/meta/io.murano/Classes/Environment.yaml index d4e4a907..19b5ae8e 100644 --- a/meta/io.murano/Classes/Environment.yaml +++ b/meta/io.murano/Classes/Environment.yaml @@ -38,9 +38,8 @@ Properties: defaultNetworks: Contract: - environment: $.class(res:Network) - flat: $.class(res:Network) - Usage: In + environment: $.template(res:Network) + flat: $.template(res:Network) securityGroupManager: Contract: $.class(sys:SecurityGroupManager) @@ -67,33 +66,53 @@ Properties: Contract: $.string() Usage: InOut + homeRegionName: + Contract: $.string() + Usage: Runtime + + regions: + Contract: + $.string(): $.class(CloudRegion) + Usage: InOut + Methods: - initialize: + .init: Body: + - $.homeRegionName: config(home_region) or '' - $._assignRegions() - - $generatedEnvironmentName: $.getAttr(generatedEnvironmentName) - - If: $generatedEnvironmentName = null + - $.instanceNotifier: new(sys:InstanceNotifier, environment => $this) + - $.reporter: new(sys:StatusReporter, environment => $this) + - $.regions: $.regions + $.regionConfigs.keys(). + where($ and not $this.regions.containsKey($)). + select($this._createRegion($)). + toDict($.name) + - If: not $.regions.containsKey(null) Then: - - $generatedEnvironmentName: randomName() - - $.setAttr(generatedEnvironmentName, $generatedEnvironmentName) - - $this.agentListener: new(sys:AgentListener, $this, name => $generatedEnvironmentName) - - $stackDescriptionFormat: 'This stack was generated by Murano for environment {0} (ID: {1})' - - $this.stack: new(sys:HeatStack, $this, - name => 'murano-' + $generatedEnvironmentName, - description => $stackDescriptionFormat.format($.name, $.id())) - - $this.instanceNotifier: new(sys:InstanceNotifier, environment => $this) - - $this.reporter: new(sys:StatusReporter, environment => $this) - - $net: null - - If: $.defaultNetworks.environment != null - Then: - - $net: $.defaultNetworks.environment - - If: $.defaultNetworks.flat != null - Then: - - $net: $.defaultNetworks.flat - - If: $net != null - Then: - - $this.securityGroupManager: $net.generateSecurityGroupManager($this) + - If: $.homeRegionName + Then: + $.regions['']: $.regions[$.homeRegionName] + Else: + $.regions['']: $._createRegion('') + + - $defaultRegion: $.regions[''] + - $.stack: $defaultRegion.stack + - $.securityGroupManager: $defaultRegion.securityGroupManager + + _createRegion: + Arguments: + regionName: + Contract: $.string() + Body: + - $envNet: $.defaultNetworks.environment?.set(regionName => $regionName) + - $flatNet: $.defaultNetworks.flat?.set(regionName => $regionName) + - Return: new(CloudRegion, $this, + name => $regionName, + defaultNetworks => { + environment => $envNet, + flat => $flatNet + } + ) deploy: Usage: Action @@ -106,10 +125,9 @@ Methods: _assignRegions: Body: - - $homeRegion: config(home_region) - If: $.region = null Then: - $.region: $homeRegion + $.region: $.homeRegionName - $defaultRegionConfig: agentRabbitMq: @@ -120,10 +138,10 @@ Methods: virtual_host: config(rabbitmq, virtual_host) ssl: config(rabbitmq, ssl) - - If: not (null in $.regionConfigs.keys()) + - If: not $.regionConfigs.containsKey('') Then: - - $.regionConfigs: $.regionConfigs.set(null => $defaultRegionConfig) + - $.regionConfigs: $.regionConfigs.set('' => $defaultRegionConfig) - - If: $homeRegion != null and not ($homeRegion in $.regionConfigs.keys()) + - If: $.homeRegionName and not $.regionConfigs.containsKey($.homeRegionName) Then: - - $.regionConfigs: $.regionConfigs.set($homeRegion => $defaultRegionConfig) + - $.regionConfigs: $.regionConfigs.set($.homeRegionName => $defaultRegionConfig) diff --git a/meta/io.murano/Classes/SharedIp.yaml b/meta/io.murano/Classes/SharedIp.yaml index adf5e218..5bfe6abf 100644 --- a/meta/io.murano/Classes/SharedIp.yaml +++ b/meta/io.murano/Classes/SharedIp.yaml @@ -29,8 +29,9 @@ Properties: Methods: initialize: Body: - - $.environment: $.find(Environment).require() - - $.network: $.environment.defaultNetworks.environment + - $._environment: $.find(Environment).require() + - $._region: $.getRegion() + - $.network: $._environment.defaultNetworks.environment - $.instances: [] @@ -38,10 +39,10 @@ Methods: Body: - If: not $.getAttr(deployed, false) Then: - - $reporter: $.environment.reporter + - $reporter: $._environment.reporter - $.network.deploy() - $networkData: $.network.describe() - - $aapPortName: format('AllowedAddressPairsPort-{0}', $.id()) + - $aapPortName: format('AllowedAddressPairsPort-{0}', id($)) - $template: resources: $aapPortName: @@ -55,12 +56,12 @@ Methods: $aapPortName+'-virtualIp': value: get_attr: [$aapPortName, fixed_ips, 0, ip_address] - description: format('SharedIP Address of SharedIp group {0}', $.id()) - - $.environment.stack.updateTemplate($template) + description: format('SharedIP Address of SharedIp group {0}', id($)) + - $._region.stack.updateTemplate($template) - If: $.assignFloatingIp Then: - $extNetId: $networkData.floatingIpNetId - - $fipName: format('Shared-Floating-ip-{0}', $.id()) + - $fipName: format('Shared-Floating-ip-{0}', id($)) - $template: resources: @@ -75,13 +76,13 @@ Methods: value: get_attr: [$fipName, floating_ip_address] description: Shared Floating IP assigned - - $.environment.stack.updateTemplate($template) + - $._region.stack.updateTemplate($template) - $reporter.report($this, 'Allocating shared ip address') - - $.environment.stack.push() - - $outputs: $.environment.stack.output() - - $.virtualIp: $outputs.get(format('AllowedAddressPairsPort-{0}-virtualIp', $.id())) - - $.floatingIpAddress: $outputs.get(format('Shared-Floating-ip-{0}-val', $.id())) + - $._region.stack.push() + - $outputs: $._region.stack.output() + - $.virtualIp: $outputs.get(format('AllowedAddressPairsPort-{0}-virtualIp', id($))) + - $.floatingIpAddress: $outputs.get(format('Shared-Floating-ip-{0}-val', id($))) - $reporter.report($this, format('Shared IP allocated at {0}', $.virtualIp)) - If: $.assignFloatingIp Then: @@ -91,21 +92,21 @@ Methods: getSharedIpRef: Body: - - $aapPortName: format('AllowedAddressPairsPort-{0}', $.id()) + - $aapPortName: format('AllowedAddressPairsPort-{0}', id($)) - Return: get_attr: [$aapPortName, fixed_ips, 0, ip_address] releaseResources: Body: - - $template: $.environment.stack.current() + - $template: $._region.stack.current() - $template.resources: $template.resources.delete(format('AllowedAddressPairsPort-{0}', id($))) - $template.outputs: $template.outputs.delete(format('AllowedAddressPairsPort-{0}-virtualIp', id($))) - If: $.assignFloatingIp Then: - $template.resources: $template.resources.delete(format('Shared-Floating-ip-{0}', id($))) - $template.outputs: $template.outputs.delete(format('Shared-Floating-ip-{0}-val', id($))) - - $._environment.stack.setTemplate($template) - - $._environment.stack.push() + - $._region.stack.setTemplate($template) + - $._region.stack.push() - $.floatingIpAddress: null - $.virtualIp: null diff --git a/meta/io.murano/Classes/resources/CinderVolume.yaml b/meta/io.murano/Classes/resources/CinderVolume.yaml index 4d4d5f4b..eec1f058 100644 --- a/meta/io.murano/Classes/resources/CinderVolume.yaml +++ b/meta/io.murano/Classes/resources/CinderVolume.yaml @@ -52,6 +52,7 @@ Methods: .init: Body: - $._environment: $.find(std:Environment).require() + - $._region: $.getRegion() buildResourceDefinition: Body: @@ -111,11 +112,11 @@ Methods: - $snippet: $.buildResourceDefinition() - If: $.getAttr(lastTemplate) != $snippet Then: - - $template: $._environment.stack.current() + - $template: $._region.stack.current() - $template: $template.mergeWith($snippet, maxLevels => 2) - - $._environment.stack.setTemplate($template) - - $._environment.stack.push() - - $outputs: $._environment.stack.output() + - $._region.stack.setTemplate($template) + - $._region.stack.push() + - $outputs: $._region.stack.output() - $.openstackId: $outputs.get(format('vol-{0}-id', id($))) - $.setAttr(lastTemplate, $snippet) @@ -123,11 +124,11 @@ Methods: Body: - If: $.getAttr(lastTemplate) != null Then: - - $template: $._environment.stack.current() + - $template: $._region.stack.current() - $template.resources: $template.resources.delete(format('vol-{0}', id($))) - $template.outputs: $template.outputs.delete(format('vol-{0}-id', id($))) - - $._environment.stack.setTemplate($template) - - $._environment.stack.push() + - $._region.stack.setTemplate($template) + - $._region.stack.push() - $.setAttr(lastTemplate, null) - $.openstackId: null diff --git a/meta/io.murano/Classes/resources/ConfLangInstance.yaml b/meta/io.murano/Classes/resources/ConfLangInstance.yaml index 482a23a6..92d44048 100644 --- a/meta/io.murano/Classes/resources/ConfLangInstance.yaml +++ b/meta/io.murano/Classes/resources/ConfLangInstance.yaml @@ -21,7 +21,7 @@ Methods: - userData: Contract: $.string().notNull() Body: - - $environment: $.find(std:Environment).require() + - $region: $.getRegion() - $cloudInitConf: $.generateCloudConfig() - $bootConfigResourceName: format('boot_config_{0}', $.name) - $bootScriptResourceName: format('boot_script_{0}', $.name) @@ -44,14 +44,13 @@ Methods: - config: {get_resource: $bootConfigResourceName} - config: {get_resource: $bootScriptResourceName} - - $environment.stack.updateTemplate($template) + - $region.stack.updateTemplate($template) - Return: {get_resource: $userDataResourceName} generateCloudConfig: Body: - - $resources: new(sys:Resources) - - $cloudConfigData: $.cast(LinuxMuranoInstance).generateCloudConfig() - - $confLang: $resources.yaml('conflang.conf') - - $cloudInitConf: $cloudConfigData.mergeWith($confLang) - - Return: $cloudInitConf + - $cloudConfigData: cast($, LinuxMuranoInstance).generateCloudConfig() + - $confLang: sys:Resources.yaml('conflang.conf') + - $cloudInitConf: $cloudConfigData.mergeWith($confLang) + - Return: $cloudInitConf diff --git a/meta/io.murano/Classes/resources/ExistingNeutronNetwork.yaml b/meta/io.murano/Classes/resources/ExistingNeutronNetwork.yaml index a7939b87..8e969476 100644 --- a/meta/io.murano/Classes/resources/ExistingNeutronNetwork.yaml +++ b/meta/io.murano/Classes/resources/ExistingNeutronNetwork.yaml @@ -130,7 +130,7 @@ Workflow: - If: $assignFloatingIp Then: - $floatingIpNetRef: $._externalNetworkId - - $fipName: format('fip-{0}-{1}', $.id(), $instance.name) + - $fipName: format('fip-{0}-{1}', id($), $instance.name) - Return: $.joinInstanceToNetwork( instance => $instance, diff --git a/meta/io.murano/Classes/resources/HeatSWConfigInstance.yaml b/meta/io.murano/Classes/resources/HeatSWConfigInstance.yaml index 4fbea29c..f7303864 100644 --- a/meta/io.murano/Classes/resources/HeatSWConfigInstance.yaml +++ b/meta/io.murano/Classes/resources/HeatSWConfigInstance.yaml @@ -124,7 +124,6 @@ Methods: instanceTemplate: Contract: {} Body: - - $environment: $.find(std:Environment) - For: fragment In: $.softwareConfigs Do: @@ -139,13 +138,13 @@ Methods: releaseResources: Body: - - $environment: $.find(std:Environment) - - $template: $environment.stack.current() - - If: bool($template.resources) and bool($template.outputs) + - $region: $.getRegion() + - $template: $region.stack.current() + - If: $template.get(resources) and $template.get(outputs) Then: - $template.resources: $template.resources.deleteAll($.getAttr(scResources, [])) - $template.outputs: $template.outputs.deleteAll($.getAttr(scOutputs, [])) - - $environment.stack.setTemplate($template) - - $.super($.releaseResources()) + - $region.stack.setTemplate($template) + - super($, $.releaseResources()) - $.setAttr(scResources, []) - $.setAttr(scOutputs, []) diff --git a/meta/io.murano/Classes/resources/Instance.yaml b/meta/io.murano/Classes/resources/Instance.yaml index 6ae243f0..50e838ac 100644 --- a/meta/io.murano/Classes/resources/Instance.yaml +++ b/meta/io.murano/Classes/resources/Instance.yaml @@ -17,7 +17,7 @@ Namespaces: Name: Instance - +Extends: std:CloudResource Properties: name: @@ -80,7 +80,7 @@ Properties: Methods: initialize: Body: - - $.environment: $.find(std:Environment).require() + - $._environment: $.find(std:Environment).require() - $.agent: new(sys:Agent, host => $) - $.resources: new(sys:Resources) - $.instanceTemplate: {} @@ -106,26 +106,28 @@ Methods: beginDeploy: Body: - $.validateBootSource() + - $region: $.getRegion() - $securityGroupName: coalesce( $.securityGroupName, - $.environment.securityGroupManager.defaultGroupName + $region.securityGroupManager.defaultGroupName ) - $.createDefaultInstanceSecurityGroupRules($securityGroupName) - $.detectPrimaryNetwork() - $.ensureSharedIpsDeployed() - $.ensureNetworksDeployed() - - If: $.networks.useEnvironmentNetwork and $.environment.defaultNetworks.environment!=null + - If: $.networks.useEnvironmentNetwork and $region.defaultNetworks.environment!=null Then: - $.joinNet($.environment.defaultNetworks.environment, $securityGroupName) - - If: $.networks.useFlatNetwork and $.environment.defaultNetworks.flat!=null + $.joinNet($region.defaultNetworks.environment, $securityGroupName) + - If: $.networks.useFlatNetwork and $region.defaultNetworks.flat!=null Then: - $.joinNet($.environment.defaultNetworks.flat, $securityGroupName) + $.joinNet($region.defaultNetworks.flat, $securityGroupName) - $.networks.customNetworks.select($this.joinNet($, $securityGroupName)) - $preparedUserData: $.prepareUserData() # Create MQ queue to communicate with the VM - $.agent.prepare() - $properties: + name: $.name flavor: $.flavor availability_zone: $.availabilityZone user_data: $preparedUserData.data @@ -161,12 +163,13 @@ Methods: # Any additional template preparation - $.instanceTemplate: $.prepareStackTemplate($.instanceTemplate) - - $.environment.stack.updateTemplate($.instanceTemplate) + - $region.stack.updateTemplate($.instanceTemplate) endDeploy: Body: - - $.environment.stack.push() - - $outputs: $.environment.stack.output() + - $region: $.getRegion() + - $region.stack.push() + - $outputs: $region.stack.output() - $.ipAddresses: $outputs.get(format('{0}-assigned-ips', $this.name)).values().flatten().distinct() - $.openstackId: $outputs.get(format('{0}-id', $this.name)) - If: $._floatingIpOutputName != null @@ -174,7 +177,7 @@ Methods: - $.floatingIpAddress: $outputs.get($._floatingIpOutputName) - If: $.floatingIpAddress != null Then: $.setAttr(fipAssigned, true) - - $.environment.instanceNotifier.trackCloudInstance($this) + - $._environment.instanceNotifier.trackCloudInstance($this) deploy: Body: @@ -183,18 +186,19 @@ Methods: detectPrimaryNetwork: Body: + - $region: $.getRegion() - $._primaryNetwork: null - If: $.networks.primaryNetwork != null Then: - $._primaryNetwork: $.networks.primaryNetwork Else: - - If: $.networks.useEnvironmentNetwork and $.environment.defaultNetworks.environment!=null + - If: $.networks.useEnvironmentNetwork and $region.defaultNetworks.environment!=null Then: - - $._primaryNetwork: $.environment.defaultNetworks.environment + - $._primaryNetwork: $region.defaultNetworks.environment Else: - - If: $.networks.useFlatNetwork and $.environment.defaultNetworks.flat!=null + - If: $.networks.useFlatNetwork and $region.defaultNetworks.flat!=null Then: - - $._primaryNetwork: $.environment.defaultNetworks.flat + - $._primaryNetwork: $region.defaultNetworks.flat Else: - If: $.networks.customNetworks!= null Then: @@ -202,12 +206,13 @@ Methods: ensureNetworksDeployed: Body: - - If: $.networks.useEnvironmentNetwork and $.environment.defaultNetworks.environment!=null + - $region: $.getRegion() + - If: $.networks.useEnvironmentNetwork and $region.defaultNetworks.environment!=null Then: - - $.environment.defaultNetworks.environment.deploy() - - If: $.networks.useFlatNetwork and $.environment.defaultNetworks.flat!=null + - $region.defaultNetworks.environment.deploy() + - If: $.networks.useFlatNetwork and $region.defaultNetworks.flat!=null Then: - - $.environment.defaultNetworks.flat.deploy() + - $region.defaultNetworks.flat.deploy() - $.networks.customNetworks.pselect($.deploy()) ensureSharedIpsDeployed: @@ -250,7 +255,7 @@ Methods: - port: $joinResult.portRef - $.instanceTemplate: $.instanceTemplate.mergeWith($template) - - If: $joinResult.secGroupName != null + - If: $joinResult.get(secGroupName) != null Then: - $template: resources: @@ -293,29 +298,31 @@ Methods: beginReleaseResources: Body: - - $template: $.environment.stack.current() - - If: bool($template.resources) and bool($template.outputs) + - $region: $.getRegion() + - $template: $region.stack.current() + - If: $template.get(resources) and $template.get(outputs) Then: - $resourcesToDelete: list($.name).concat($.getAttr(instanceResources, [])) - $lenBefore: len($template.resources) - $template.resources: $template.resources.deleteAll($resourcesToDelete) - If: $lenBefore > len($template.resources) Then: - - $.environment.instanceNotifier.untrackCloudInstance($this) + - $._environment.instanceNotifier.untrackCloudInstance($this) - $outputsToDelete: list( '{0}-assigned-ips'.format($.name), '{0}-id'.format($.name)).concat($.getAttr(instanceOutputs, [])) - $template.outputs: $template.outputs.deleteAll($outputsToDelete) - - $.environment.stack.setTemplate($template) + - $region.stack.setTemplate($template) endReleaseResources: Body: - - $template: $.environment.stack.current() - - If: bool($template.resources) and bool($template.outputs) + - $region: $.getRegion() + - $template: $region.stack.current() + - If: $template.get(resources) and $template.get(outputs) Then: - - $.environment.stack.push() + - $region.stack.push() - $.setAttr(instanceResources, []) - $.setAttr(instanceOutputs, []) - $.setAttr(fipAssigned, false) @@ -360,8 +367,9 @@ Methods: isDeployed: Body: - - $template: $.environment.stack.current() - - Return: $template.resources != null and $.name in $template.resources + - $region: $.getRegion() + - $template: $region.stack.current() + - Return: $template.get(resources, {}).containsKey($.name) getRef: Body: diff --git a/meta/io.murano/Classes/resources/LinuxInstance.yaml b/meta/io.murano/Classes/resources/LinuxInstance.yaml index 04a91c46..316f669a 100644 --- a/meta/io.murano/Classes/resources/LinuxInstance.yaml +++ b/meta/io.murano/Classes/resources/LinuxInstance.yaml @@ -24,11 +24,11 @@ Methods: - groupName: Contract: $.string().notNull() Body: - - $environment: $.find(std:Environment).require() + - $region: $.getRegion() - $rules: - ToPort: 22 IpProtocol: tcp FromPort: 22 External: true - - $environment.securityGroupManager.addGroupIngress( + - $region.securityGroupManager.addGroupIngress( rules => $rules, groupName => $groupName) diff --git a/meta/io.murano/Classes/resources/LinuxMuranoInstance.yaml b/meta/io.murano/Classes/resources/LinuxMuranoInstance.yaml index 62d3d73b..b061df0b 100644 --- a/meta/io.murano/Classes/resources/LinuxMuranoInstance.yaml +++ b/meta/io.murano/Classes/resources/LinuxMuranoInstance.yaml @@ -21,7 +21,7 @@ Methods: - userData: Contract: $.string().notNull() Body: - - $environment: $.find(std:Environment).require() + - $region: $.getRegion() - $resources: new(sys:Resources) - $muranoInitConf: $.generateCloudConfig() - $bootScriptResourceName: format('boot_script_{0}', $.name) @@ -46,7 +46,7 @@ Methods: - config: {get_resource: $bootScriptResourceName} - $.setAttr(resourceCloudConfig, [$bootScriptResourceName, $userDataResourceName, $bootConfigResourceName]) - - $environment.stack.updateTemplate($template) + - $region.stack.updateTemplate($template) - Return: {get_resource: $userDataResourceName} @@ -58,9 +58,8 @@ Methods: generateUserData: Body: - - $environment: $.find(std:Environment).require() - - $rabbitMqParams: $environment.regionConfigs.get($environment.region, - $environment.regionConfigs.get(null)).agentRabbitMq + - $region: $.getRegion() + - $rabbitMqParams: $region.getConfig().agentRabbitMq - $resources: new(sys:Resources) - $configFile: $resources.string('Agent-v2.template') - $initScript: $resources.string('linux-init.sh') @@ -77,7 +76,7 @@ Methods: "%RABBITMQ_SSL%": str($rabbitMqParams.ssl).toLower() "%RABBITMQ_INSECURE%": str($rabbitMqParams.insecure).toLower() "%RABBITMQ_INPUT_QUEUE%": $.agent.queueName() - "%RESULT_QUEUE%": $environment.agentListener.queueName() + "%RESULT_QUEUE%": $region.agentListener.queueName() - $scriptReplacements: "%AGENT_CONFIG_BASE64%": base64encode($configFile.replace($configReplacements)) "%INTERNAL_HOSTNAME%": $.name @@ -97,12 +96,12 @@ Methods: releaseResources: Body: - - $environment: $.find(std:Environment).require() - - $template: $environment.stack.current() - - If: bool($template.resources) and bool($template.outputs) + - $region: $.getRegion() + - $template: $region.stack.current() + - If: $template.get(resources) and $template.get(outputs) Then: - $resourcesToDelete: $.getAttr(resourceCloudConfig, []) - $template.resources: $template.resources.deleteAll($resourcesToDelete) - - $environment.stack.setTemplate($template) + - $region.stack.setTemplate($template) - - $.super($.releaseResources()) \ No newline at end of file + - super($, $.releaseResources()) \ No newline at end of file diff --git a/meta/io.murano/Classes/resources/Network.yaml b/meta/io.murano/Classes/resources/Network.yaml index d913f0c0..cba20c6e 100644 --- a/meta/io.murano/Classes/resources/Network.yaml +++ b/meta/io.murano/Classes/resources/Network.yaml @@ -15,6 +15,7 @@ Namespaces: std: io.murano Name: Network +Extends: std:CloudResource Methods: deploy: @@ -32,8 +33,5 @@ Methods: - $.class(std:SharedIp) generateSecurityGroupManager: - Arguments: - - environment: - Contract: $.class(std:Environment).notNull() describe: \ No newline at end of file diff --git a/meta/io.murano/Classes/resources/NeutronNetwork.yaml b/meta/io.murano/Classes/resources/NeutronNetwork.yaml index 85a94c72..16cfad6a 100644 --- a/meta/io.murano/Classes/resources/NeutronNetwork.yaml +++ b/meta/io.murano/Classes/resources/NeutronNetwork.yaml @@ -50,10 +50,10 @@ Properties: Usage: InOut Methods: - initialize: + .init: Body: - - $._environment: $.find(std:Environment).require() - - $._netExplorer: new(sys:NetworkExplorer, $._environment) + - $._region: $.getRegion() + - $._netExplorer: new(sys:NetworkExplorer, $this) deploy: @@ -69,16 +69,16 @@ Methods: - $.externalRouterId: $._netExplorer.getDefaultRouter() - If: $.autogenerateSubnet and (not bool($.subnetCidr)) Then: - - $.subnetCidr: $._netExplorer.getAvailableCidr($.externalRouterId, $.id()) + - $.subnetCidr: $._netExplorer.getAvailableCidr($.externalRouterId, id($)) - $template: $template.mergeWith($._createSubnet()) - If: $.externalRouterId != null Then: - $template: $template.mergeWith($._createRouterInterface()) - - $._environment.stack.updateTemplate($template) - - $._environment.stack.push() - - $outputs: $._environment.stack.output() + - $._region.stack.updateTemplate($template) + - $._region.stack.push() + - $outputs: $._region.stack.output() - $.openstackId: $outputs.get(format('{0}-id', $this.name)) - $.setAttr(deployed, true) @@ -91,7 +91,7 @@ Methods: $netName: type: 'OS::Neutron::Net' properties: - name: format('{0}-{1}', $.name, $.id()) + name: format('{0}-{1}', $.name, id($)) outputs: format('{0}-id', $.name): description: format('ID of {0} network', $.name) @@ -144,7 +144,7 @@ Methods: - If: $assignFloatingIp Then: - $extNetId: $._getExternalNetId() - - $fipName: format('fip-{0}-{1}', $.id(), $instance.name) + - $fipName: format('fip-{0}-{1}', id($), $instance.name) - $result: $.joinInstanceToNetwork( instance => $instance, @@ -186,9 +186,9 @@ Methods: releaseResources: Body: - - $template: $.environment.stack.current() + - $template: $._region.stack.current() - - $template.resources: $template.resources.delete(format('{0}-{1}', $.name, $.id())) + - $template.resources: $template.resources.delete(format('{0}-{1}', $.name, id($))) - $template.resources: $template.resources.delete($._getSubnetName()) - $template.outputs: $template.outputs.delete(format('{0}-id', $.name)) @@ -197,24 +197,24 @@ Methods: Then: $template.resources: $template.resources.delete($._getRouterInterfaceName()) - - $._environment.stack.setTemplate($template) - - $._environment.stack.push() + - $._regiont.stack.setTemplate($template) + - $._region.stack.push() - $.openstackId: null _getRouterInterfaceName: Body: - Return: format('ri-{0}', $.id()) + Return: format('ri-{0}', id($)) _getNetworkName: Body: - Return: format('network-{0}', $.id()) + Return: format('network-{0}', id($)) _getSubnetName: Body: - Return: format('subnet-{0}', $.id()) + Return: format('subnet-{0}', id($)) _getExternalNetId: diff --git a/meta/io.murano/Classes/resources/NeutronNetworkBase.yaml b/meta/io.murano/Classes/resources/NeutronNetworkBase.yaml index 481003c5..9e93c2d0 100644 --- a/meta/io.murano/Classes/resources/NeutronNetworkBase.yaml +++ b/meta/io.murano/Classes/resources/NeutronNetworkBase.yaml @@ -20,8 +20,10 @@ Name: NeutronNetworkBase Extends: Network Methods: - initialize: + .init: Body: + - $._environment: $.find(std:Environment) + - $._region: $.getRegion() - $._netExplorer: new(sys:NetworkExplorer, $this) - $._securityGroupsEnabled: $._netExplorer.listNeutronExtensions().alias.contains('security-group') @@ -43,7 +45,7 @@ Methods: - floatingIpNetRef: Contract: $ Body: - - $portName: format('port-{0}-{1}', $.id(), $instance.name) + - $portName: format('port-{0}-{1}', id($), $instance.name) - $patchTemplate: resources: $portName: @@ -108,13 +110,10 @@ Methods: generateSecurityGroupManager: - Arguments: - - environment: - Contract: $.class(std:Environment).notNull() Body: - If: $this._securityGroupsEnabled Then: - - Return: new(sys:NeutronSecurityGroupManager, environment => $environment) + - Return: new(sys:NeutronSecurityGroupManager, $._region) Else: - - $environment.reporter.report($this, "Warning! Security groups are disabled!") - - Return: new(sys:DummySecurityGroupManager, environment => $environment) + - $._environment.reporter.report($this, "Warning! Security groups are disabled!") + - Return: new(sys:DummySecurityGroupManager, $._region) diff --git a/meta/io.murano/Classes/resources/NovaNetwork.yaml b/meta/io.murano/Classes/resources/NovaNetwork.yaml index efe77dce..b8eee115 100644 --- a/meta/io.murano/Classes/resources/NovaNetwork.yaml +++ b/meta/io.murano/Classes/resources/NovaNetwork.yaml @@ -69,11 +69,8 @@ Methods: generateSecurityGroupManager: - Arguments: - - environment: - Contract: $.class(std:Environment).notNull() Body: - - Return: new(sys:AwsSecurityGroupManager, environment => $environment) + - Return: new(sys:AwsSecurityGroupManager) describe: diff --git a/meta/io.murano/Classes/resources/Volume.yaml b/meta/io.murano/Classes/resources/Volume.yaml index c83ea1dc..07bcdef4 100644 --- a/meta/io.murano/Classes/resources/Volume.yaml +++ b/meta/io.murano/Classes/resources/Volume.yaml @@ -12,9 +12,11 @@ Namespaces: =: io.murano.resources + std: io.murano Name: Volume +Extends: std:CloudResource Properties: diff --git a/meta/io.murano/Classes/system/AwsSecurityGroupManager.yaml b/meta/io.murano/Classes/system/AwsSecurityGroupManager.yaml index 038fe4e8..dcf08625 100644 --- a/meta/io.murano/Classes/system/AwsSecurityGroupManager.yaml +++ b/meta/io.murano/Classes/system/AwsSecurityGroupManager.yaml @@ -19,6 +19,11 @@ Name: AwsSecurityGroupManager Extends: SecurityGroupManager Methods: + .init: + Body: + - $._environment: $.find(std:Environment) + - $._region: $.find(std:CloudRegion).require() + addGroupIngress: Arguments: - rules: @@ -82,19 +87,19 @@ Methods: Message: $msg - $groupDirection: dict(egress => SecurityGroupEgress).get($direction, SecurityGroupIngress) - - $stack: $.environment.stack + - $stack: $._region.stack - $template: resources: $groupName: type: 'AWS::EC2::SecurityGroup' properties: - GroupDescription: format('Composite security group of Murano environment {0}', $.environment.name) + GroupDescription: format('Composite security group of Murano environment {0}', $._environment.name) $groupDirection: - FromPort: '-1' ToPort: '-1' IpProtocol: icmp CidrIp: '0.0.0.0/0' - - $.environment.stack.updateTemplate($template) + - $._region.stack.updateTemplate($template) - $rulesList: $rules.select(dict( FromPort => str($.FromPort), @@ -109,4 +114,4 @@ Methods: type: 'AWS::EC2::SecurityGroup' properties: $groupDirection: $rulesList - - $.environment.stack.updateTemplate($template) + - $._region.stack.updateTemplate($template) diff --git a/meta/io.murano/Classes/system/NeutronSecurityGroupManager.yaml b/meta/io.murano/Classes/system/NeutronSecurityGroupManager.yaml index 18b431e8..a8690aff 100644 --- a/meta/io.murano/Classes/system/NeutronSecurityGroupManager.yaml +++ b/meta/io.murano/Classes/system/NeutronSecurityGroupManager.yaml @@ -19,6 +19,11 @@ Name: NeutronSecurityGroupManager Extends: SecurityGroupManager Methods: + .init: + Body: + - $._environment: $.find(std:Environment) + - $._region: $.find(std:CloudRegion).require() + addGroupIngress: Arguments: - rules: @@ -71,17 +76,18 @@ Methods: ext_key: remote_mode ext_val: remote_group_id - - $stack: $.environment.stack - $template: resources: $groupName: type: 'OS::Neutron::SecurityGroup' properties: - description: format('Composite security group of Murano environment {0}', $.environment.name) + description: format( + 'Composite security group of Murano environment {0}', + $._environment.name) rules: - protocol: icmp remote_ip_prefix: '0.0.0.0/0' - - $.environment.stack.updateTemplate($template) + - $._region.stack.updateTemplate($template) - $rulesList: $rules.select(dict( port_range_min => $.FromPort, @@ -98,4 +104,4 @@ Methods: type: 'OS::Neutron::SecurityGroup' properties: rules: $rulesList - - $.environment.stack.updateTemplate($template) \ No newline at end of file + - $._region.stack.updateTemplate($template) \ No newline at end of file diff --git a/meta/io.murano/Classes/system/SecurityGroupManager.yaml b/meta/io.murano/Classes/system/SecurityGroupManager.yaml index 400d1b15..c43484fc 100644 --- a/meta/io.murano/Classes/system/SecurityGroupManager.yaml +++ b/meta/io.murano/Classes/system/SecurityGroupManager.yaml @@ -17,12 +17,9 @@ Namespaces: Name: SecurityGroupManager Properties: - environment: - Contract: $.class(std:Environment).notNull() - defaultGroupName: Contract: $.string() - Default: format('MuranoSecurityGroup-{0}', $.environment.id()) + Default: id($.find(std:CloudRegion)) Methods: addGroupIngress: diff --git a/meta/io.murano/Classes/test/TestFixture.yaml b/meta/io.murano/Classes/test/TestFixture.yaml index 28d8b685..83c1634b 100644 --- a/meta/io.murano/Classes/test/TestFixture.yaml +++ b/meta/io.murano/Classes/test/TestFixture.yaml @@ -46,11 +46,8 @@ Methods: - Return: {} generateSecurityGroupManager: - Arguments: - - environment: - Contract: $.class(std:Environment).notNull() Body: - - Return: new(sys:SecurityGroupManager, environment => $environment) + - Return: new(sys:DummySecurityGroupManager) describe: Body: diff --git a/meta/io.murano/manifest.yaml b/meta/io.murano/manifest.yaml index a2c371cd..ed80970e 100644 --- a/meta/io.murano/manifest.yaml +++ b/meta/io.murano/manifest.yaml @@ -10,7 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. -Format: 1.1 +Format: 1.4 Type: Library @@ -28,6 +28,8 @@ Tags: [MuranoPL] Classes: io.murano.Object: Object.yaml io.murano.Environment: Environment.yaml + io.murano.CloudRegion: CloudRegion.yaml + io.murano.CloudResource: CloudResource.yaml io.murano.Application: Application.yaml io.murano.Exception: Exception.yaml io.murano.StackTrace: StackTrace.yaml diff --git a/murano/dsl/dsl.py b/murano/dsl/dsl.py index 9557abc4..f5311c47 100644 --- a/murano/dsl/dsl.py +++ b/murano/dsl/dsl.py @@ -162,9 +162,10 @@ class MuranoObjectInterface(dsl_types.MuranoObjectInterface): def func(*args, **kwargs): self._insert_instruction() with helpers.with_object_store(self.__object_store): - return self.__object.type.invoke( + context = helpers.get_context() + return to_mutable(self.__object.type.invoke( item, self.__object, args, kwargs, - helpers.get_context()) + context), helpers.get_yaql_engine(context)) return func @staticmethod diff --git a/murano/dsl/helpers.py b/murano/dsl/helpers.py index 7eed7509..1d9b6483 100644 --- a/murano/dsl/helpers.py +++ b/murano/dsl/helpers.py @@ -198,7 +198,7 @@ def get_current_method(context=None): def get_yaql_engine(context=None): context = context or get_context() - return context[constants.CTX_YAQL_ENGINE] + return None if context is None else context[constants.CTX_YAQL_ENGINE] def get_current_exception(context=None): diff --git a/murano/engine/system/agent.py b/murano/engine/system/agent.py index d3f3acb6..994c77e9 100644 --- a/murano/engine/system/agent.py +++ b/murano/engine/system/agent.py @@ -47,10 +47,10 @@ class Agent(object): 'by the server configuration') return - self._environment = host.find_owner('io.murano.Environment') + self._host = host self._enabled = True - self._queue = str('e%s-h%s' % ( - self._environment.id, host.id)).lower() + env = host.find_owner('io.murano.Environment') + self._queue = str('e%s-h%s' % (env.id, host.id)).lower() @property def enabled(self): @@ -63,7 +63,8 @@ class Agent(object): 'by the server configuration') return - with common.create_rmq_client(self._environment) as client: + region = dsl.MuranoObjectInterface.create(self._host().getRegion()) + with common.create_rmq_client(region) as client: client.declare(self._queue, enable_ha=True, ttl=86400000) def queue_name(self): @@ -83,14 +84,15 @@ class Agent(object): def _send(self, template, wait_results, timeout): """Send a message over the MQ interface.""" + region = self._host().getRegion() msg_id = template.get('ID', uuid.uuid4().hex) if wait_results: event = eventlet.event.Event() - listener = self._environment['agentListener'] + listener = region['agentListener'] listener().subscribe(msg_id, event) msg = self._prepare_message(template, msg_id) - with common.create_rmq_client(self._environment) as client: + with common.create_rmq_client(region) as client: client.send(message=msg, key=self._queue) if wait_results: diff --git a/murano/engine/system/agent_listener.py b/murano/engine/system/agent_listener.py index 4c4d3a22..b7cc5b39 100644 --- a/murano/engine/system/agent_listener.py +++ b/murano/engine/system/agent_listener.py @@ -68,7 +68,7 @@ class AgentListener(object): lambda: self.stop()) self._receive_thread = dsl.spawn( self._receive, - dsl.get_this().find_owner('io.murano.Environment')) + dsl.get_this().find_owner('io.murano.CloudRegion')) def stop(self): if CONF.engine.disable_murano_agent: @@ -94,8 +94,8 @@ class AgentListener(object): self._check_enabled() self._subscriptions.pop(message_id) - def _receive(self, environment): - with common.create_rmq_client(environment) as client: + def _receive(self, region): + with common.create_rmq_client(region) as client: client.declare(self._results_queue, enable_ha=True, ttl=86400000) with client.open(self._results_queue) as subscription: while True: diff --git a/murano/engine/system/common.py b/murano/engine/system/common.py index 14201f69..7f1422a1 100644 --- a/murano/engine/system/common.py +++ b/murano/engine/system/common.py @@ -20,10 +20,8 @@ from murano.common.messaging import mqclient CONF = cfg.CONF -def create_rmq_client(environment): - region_name = environment['region'] - region_configs = environment['regionConfigs'] - region_config = region_configs.get(region_name, region_configs[None]) - rmq_settings = region_config['agentRabbitMq'].copy() +def create_rmq_client(region): + region_config = region().getConfig() + rmq_settings = dict(region_config['agentRabbitMq']) rmq_settings['ca_certs'] = CONF.rabbitmq.ca_certs.strip() or None return mqclient.MqClient(**rmq_settings) diff --git a/murano/engine/system/heat_stack.py b/murano/engine/system/heat_stack.py index 685b3a9d..d21debf3 100644 --- a/murano/engine/system/heat_stack.py +++ b/murano/engine/system/heat_stack.py @@ -14,6 +14,7 @@ # limitations under the License. import copy +import json import eventlet import heatclient.client as hclient @@ -50,7 +51,7 @@ class HeatStack(object): self._description = description self._last_stack_timestamps = (None, None) self._tags = '' - self._owner = this.find_owner('io.murano.Environment') + self._owner = this.find_owner('io.murano.CloudRegion') @staticmethod def _create_client(session, region_name): @@ -61,7 +62,7 @@ class HeatStack(object): @property def _client(self): - region = None if self._owner is None else self._owner['region'] + region = None if self._owner is None else self._owner['name'] return self._get_client(region) @staticmethod @@ -72,7 +73,7 @@ class HeatStack(object): def _get_token_client(self): ks_session = auth_utils.get_token_client_session(conf=CONF.heat) - region = None if self._owner is None else self._owner['region'] + region = None if self._owner is None else self._owner['name'] return self._create_client(ks_session, region) def current(self): @@ -212,7 +213,7 @@ class HeatStack(object): self._template['description'] = self._description template = copy.deepcopy(self._template) - LOG.debug('Pushing: {template}'.format(template=template)) + LOG.debug('Pushing: {template}'.format(template=json.dumps(template))) while True: try: diff --git a/murano/engine/system/net_explorer.py b/murano/engine/system/net_explorer.py index 018ed52b..5734f00f 100644 --- a/murano/engine/system/net_explorer.py +++ b/murano/engine/system/net_explorer.py @@ -40,7 +40,7 @@ class NetworkExplorer(object): self._project_id = session.project_id self._settings = CONF.networking self._available_cidrs = self._generate_possible_cidrs() - self._owner = this.find_owner('io.murano.Environment') + self._region = this.find_owner('io.murano.CloudRegion') @staticmethod @session_local_storage.execution_session_memoize @@ -52,7 +52,7 @@ class NetworkExplorer(object): @property def _client(self): - region = None if self._owner is None else self._owner['region'] + region = None if self._region is None else self._region['name'] return self._get_client(region) # NOTE(starodubcevna): to avoid simultaneous router requests we use retry diff --git a/murano/tests/unit/dsl/meta/AgentTests.yaml b/murano/tests/unit/dsl/meta/AgentTests.yaml deleted file mode 100644 index 8e1a74c5..00000000 --- a/murano/tests/unit/dsl/meta/AgentTests.yaml +++ /dev/null @@ -1,16 +0,0 @@ -Name: AgentTests - -Namespaces: - sys: io.murano.system - -Properties: - agent: - Contract: $.class(sys:Agent) - Usage: Runtime - - -Methods: - testAgent: - Body: - - $.agent: new(sys:Agent, host => $) - - Return: $.agent diff --git a/murano/tests/unit/dsl/test_agent.py b/murano/tests/unit/dsl/test_agent.py index ee1dc174..a21f8e6a 100644 --- a/murano/tests/unit/dsl/test_agent.py +++ b/murano/tests/unit/dsl/test_agent.py @@ -60,36 +60,20 @@ class TestAgentListener(test_case.DslTestCase): class TestAgent(test_case.DslTestCase): - def setUp(self): - super(TestAgent, self).setUp() - - # Register Agent class - self.package_loader.load_package('io.murano', None).register_class( - agent.Agent) - model = om.Object( - 'AgentTests') - self.runner = self.new_runner(model) - def test_agent_enabled(self): self.override_config('disable_murano_agent', False, 'engine') - m = mock.MagicMock() - # Necessary because otherwise there'll be an Environment lookup agent_cls = 'murano.engine.system.agent.Agent' - obj_if_cls = 'murano.dsl.dsl.MuranoObjectInterface' - with mock.patch(obj_if_cls + '.find_owner') as f: - f.return_value = m - a = self.runner.testAgent().extension - self.assertTrue(a.enabled) - self.assertEqual(m, a._environment) + a = agent.Agent(mock.MagicMock()) + self.assertTrue(a.enabled) - with mock.patch(agent_cls + '._send') as s: - s.return_value = mock.MagicMock() - a.send_raw({}) - s.assert_called_with({}, False, 0) + with mock.patch(agent_cls + '._send') as s: + s.return_value = mock.MagicMock() + a.send_raw({}) + s.assert_called_with({}, False, 0) def test_agent_disabled(self): self.override_config('disable_murano_agent', True, 'engine') - a = self.runner.testAgent().extension + a = agent.Agent(mock.MagicMock()) self.assertFalse(a.enabled) self.assertRaises(exc.PolicyViolationException, a.call, {}, None) self.assertRaises(exc.PolicyViolationException, a.send, {}, None) diff --git a/releasenotes/notes/multi-regional-apps-b64afbaeafd5b9c5.yaml b/releasenotes/notes/multi-regional-apps-b64afbaeafd5b9c5.yaml new file mode 100644 index 00000000..ea392885 --- /dev/null +++ b/releasenotes/notes/multi-regional-apps-b64afbaeafd5b9c5.yaml @@ -0,0 +1,14 @@ +--- +features: + - Support for application deployment across OpenStack regions was added. + Now all OpenStack resource classes inherit CloudResource that provides + getRegion method and regionName property. This allows to assign resources + to different regions. getRegion() returns CloudRegion instance that + resource or it parent belong to. CloudRegion has the similar interface + to Environment class and is the correct way to get HeatStack instance + associated with the regoin, default network configuration, security + group manager and agent listener instances. Environment acts as the + default region so backward compatibility is not broken. However new + applications should not use environment to set security group rules but + rather a region(s) of their instance(s) in order to work correctly when + their instances were configured to use region other then the default.