diff options
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/extensions')
46 files changed, 13099 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/__init__.py new file mode 100644 index 0000000..ff4fa7d --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/__init__.py @@ -0,0 +1,56 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os.path + +from aria import extension + +from .simple_v1_0 import ToscaSimplePresenter1_0 +from .simple_nfv_v1_0 import ToscaSimpleNfvPresenter1_0 + + +@extension.parser +class ParserExtensions(object): + + @staticmethod + def presenter_class(): + return ToscaSimplePresenter1_0, ToscaSimpleNfvPresenter1_0 + + @staticmethod + def specification_package(): + return 'aria_extension_tosca' + + @staticmethod + def specification_url(): + return { + 'yaml-1.1': 'http://yaml.org', + 'tosca-simple-1.0': 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/' + 'cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html', + 'tosca-simple-nfv-1.0': 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/' + 'tosca-nfv-v1.0.html' + } + + @staticmethod + def uri_loader_prefix(): + the_dir = os.path.dirname(__file__) + return os.path.join(the_dir, 'profiles') + + +MODULES = ( + 'simple_v1_0', + 'simple_nfv_v1_0') + +__all__ = ( + 'MODULES',) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml new file mode 100644 index 0000000..e421150 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml @@ -0,0 +1,97 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +policy_types: + + aria.Plugin: + _extensions: + shorthand_name: Plugin + type_qualified_name: aria:Plugin + role: plugin + description: >- + Policy used to specify plugins used by services. For an operation to be able to use a plugin + it must have a matching policy. The name of the policy must be the name of the plugin. The + optional properties can be used to further specify plugin selection by the orchestrator. + derived_from: tosca.policies.Root + properties: + version: + description: >- + Minimum plugin version. + type: version + required: false + enabled: + description: >- + If the policy is to disable the plugin then it will be ignored and all operations and + workflows depending on it will also be disabled. + type: boolean + default: true + + aria.Workflow: + _extensions: + shorthand_name: Workflow + type_qualified_name: aria:Workflow + role: workflow + description: >- + Policy used to specify custom workflows. A workflow is usually a workload of interconnected + calls to operations on nodes and relationships in the service topology. The name of the policy + is used as the name of the workflow. Note that it can be the same name as one of the normative + lifecycle workflows ("install", "uninstall", etc.), in which case it would be considered an + override of the default behavior. If the workflow requires parameters then this base type + should be inherited and extended with additional properties. + derived_from: tosca.policies.Root + properties: + implementation: + description: >- + The interpretation of the implementation string depends on the orchestrator. In ARIA it is + the full path to a Python @workflow function that generates a task graph based on the + service topology. + type: string + + aria.Scaling: + _extensions: + type_qualified_name: aria:Scaling + role: scaling + description: >- + Scaling. + derived_from: tosca.policies.Scaling + properties: + min_instances: + description: >- + This property is used to indicate the minimum number of instances that should be created + for the associated TOSCA Node Template by a TOSCA orchestrator. + type: integer + default: 1 + constraints: + - greater_or_equal: 0 + max_instances: + description: >- + This property is used to indicate the maximum number of instances that should be created + for the associated TOSCA Node Template by a TOSCA orchestrator. + type: integer + default: 1 + constraints: + - greater_or_equal: 0 + default_instances: + description: >- + An optional property that indicates the requested default number of instances that should + be the starting number of instances a TOSCA orchestrator should attempt to allocate. Note: + The value for this property MUST be in the range between the values set for + "min_instances" and "max_instances" properties. + type: integer + constraints: + - greater_or_equal: 0 + required: false + targets: + - tosca.nodes.Root diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/azure-plugin/azureplugin.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/azure-plugin/azureplugin.yaml new file mode 100644 index 0000000..77b61b5 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/azure-plugin/azureplugin.yaml @@ -0,0 +1,1981 @@ +# +# Copyright (c) 2017 GigaSpaces Technologies Ltd. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +tosca_definitions_version: tosca_simple_yaml_1_0 + + +topology_template: + policies: + cloudify-azure-plugin: + description: >- + azure plugin executes operations. + type: aria.Plugin + properties: + version: 1.4.2 + + +data_types: + + aria.azure.datatypes.Config: + description: >- + azure configuration + properties: + subscription_id: + description: > + A Microsoft Azure subscription ID. This is a unique + user account in Azure. This can be found in the + Subscriptions tab on your dashboard. + type: string + required: false + tenant_id: + description: > + A Microsoft Azure tenant ID. This can be found in + the Azure Active Directory dashboard by accessing + your directory. Open the Application Endpoints + dialog and your tenant ID will be in the URL for + the OAUTH2.0 TOKEN ENDPOINT. + type: string + required: false + client_id: + description: > + A Microsoft Azure client ID. This can be found in + the Azure Active Directory dashboard by accessing + your directory. View the Applications tab and select + the application used to access Azure APIs. Your + client ID can be found by expanding the ACCESS WEB + APIS IN OTHER APPLICATIONS tab. + type: string + required: false + client_secret: + description: > + A Microsoft Azure client secret key. This can be found + or generated in the same location as your client ID. + type: string + required: false + scale_name_separator: + description: > + When scaling resources, a unique name must be sent to + the Azure API. Since names are left to the user to + manage (the service does not generate unique IDs), + this plugin will attempt to append characters or + numbers to the end of the resource name when resources + are scaled out. This value should be a character, or + characters, that will separate the base name from the + generated unique characters. For instance, if the + base name of a resource is "myvm", the separator is + set to "_", and a scale workflow attempts to create + another resource, the resulting name could be + something like "myvm_1". This field can be left blank. + type: string + required: false + default: "_" + scale_name_suffix_chars: + description: > + A string of characters (ASCII) to be used when + generating unique suffix data when scaling resources. + See "scale_name_separator" for more information. + type: string + required: true + default: "1234567890" + + aria.azure.datatypes.AgentConfig: + properties: + install_method: + type: string + required: false + port: + type: integer + required: false + + + aria.azure.datatypes.StorageAccountConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163564.aspx + properties: + accountType: + description: > + An storage account type (case sensitive) + type: string + default: Standard_LRS + required: true + + aria.azure.datatypes.DataDiskConfig: + properties: + container_name: + type: string + description: > + Container for the resource. + default: vhds + size: + description: > + Size of the Page Blob (Azure disk) in GiB. Maximum of 1023 GiB allowed. + type: integer + default: 20 + required: true + force_delete: + description: > + If set to true, the resource's "delete" lifecycle will purge the + Azure Data Disk from the Azure Storage Account. If false, the + Data Disk is left as-is in the Storage Account. + type: boolean + default: false + + + aria.azure.datatypes.FileShareConfig: + properties: + metadata: + description: > + Metadata (dict) for the File Share + required: false + type: string + quota: + description: > + Quote, in GiB, for the maximum size of the file share + required: false + type: integer + fail_on_exist: + description: > + If true, causes the operation to raise a NonRecoverableError if + the file share already exists. If false, issues a warning and + continues execution. + default: false + type: boolean + + aria.azure.datatypes.AddressSpace: + description: > + Contains the address prefix,typically network CIDR + properties: + addressPrefixes: + required: true + type: list + entry_schema: string + + aria.azure.datatypes.VirtualNetworkConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163661.aspx + properties: + addressSpace: + default: + addressPrefixes: + - 172.16.0.0/16 + required: true + type: aria.azure.datatypes.AddressSpace + dhcpOptions: + required: false + type: string + subnets: + required: false + type: string + + aria.azure.datatypes.NetworkSecurityGroupConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163656.aspx + properties: + securityRules: + required: false + type: list + entry_schema: string + + + + aria.azure.datatypes.NetworkSecurityRuleConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163645.aspx + properties: + description: + type: string + required: false + protocol: + type: string + required: true + sourcePortRange: + type: string + required: false + destinationPortRange: + type: string + required: false + sourceAddressPrefix: + type: string + required: true + destinationAddressPrefix: + type: string + required: true + access: + type: string + required: true + priority: + type: integer + required: true + direction: + type: string + required: true + + aria.azure.datatypes.SubnetConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163621.aspx + properties: + addressPrefix: + type: string + required: false + networkSecurityGroup: + type: string + required: false + routeTable: + type: string + required: false + + + + + + + + aria.azure.datatypes.RouteTableConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt502548.aspx + properties: + routes: + type: string + required: false + + + aria.azure.datatypes.RouteConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt459110.aspx + properties: + addressPrefix: + type: string + required: true + nextHopType: + type: string + required: true + nextHopIpAddress: + type: string + required: false + + + aria.azure.datatype.NetworkInterfaceDnsSettings: + description: > + See https://msdn.microsoft.com/en-us/library/mt163668.aspx + properties: + appliedDnsServers: + type: list + entry_schema: string + required: false + dnsServers: + type: list + entry_schema: string + required: false + internalDnsNameLabel: + type: string + required: false + internalDomainNameSuffix: + type: string + required: false + internalFqdn: + type: string + required: false + + + aria.azure.datatypes.NetworkInterfaceCardConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163668.aspx + properties: + networkSecurityGroups: + required: false + type: string + enableIPForwarding: + required: false + type: boolean + ipConfigurations: + required: false + type: string + dnsSettings: + required: false + type: aria.azure.datatype.NetworkInterfaceDnsSettings + + + aria.azure.datatypes.IPConfigurationConfig: + properties: + privateIPAddress: + type: string + description: > + Static, private IP Address + required: false + privateIPAllocationMethod: + type: string + description: > + Defines how a private IP address is assigned. Options + are Static or Dynamic + required: true + privateIPAddressVersion: + type: string + description: > + Define the version of the IP protocol + required: false + + + aria.azure.datatypes.PublicIPAddressDnsSettings: + description: > + See https://docs.microsoft.com/en-gb/rest/api/virtualnetwork/PublicIPAddresses/CreateOrUpdate#definitions_publicipaddressdnssettings + properties: + domainNameLabel: + type: string + description: > + name refer to the VM + required: false + fqdn: + type: string + required: false + reverseFqdn: + type: string + required: false + + aria.azure.datatypes.PublicIPAddressConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163590.aspx + properties: + publicIPAllocationMethod: + type: string + description: > + Defines whether the IP address is stable or dynamic. + Options are Static or Dynamic + required: true + publicIPAddressVersion: + type: string + description: + Define the version of the public IP. + required: false + idleTimeoutInMinutes: + type: integer + description: > + Specifies the timeout (in minutes) for the TCP idle connection. + The value can be set between 4 and 30 minutes + required: false + dnsSettings: + type: aria.azure.datatypes.PublicIPAddressDnsSettings + required: false +# domainNameLabel: +# type: string +# description: > +# The concatenation of the domain name label and the regionalized +# DNS zone make up the fully qualified domain name associated +# with the public IP address. +# required: false +# reverseFqdn: +# type: string +# description: > +# A fully qualified domain name that resolves to this +# public IP address. +# required: false + + + + + + + aria.azure.datatypes.AvailabilitySetConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163607.aspx + properties: + platformUpdateDomainCount: + type: integer + required: false + platformFaultDomainCount: + type: integer + required: false + + + + aria.azure.datatypes.HardwareProfile: + properties: + vmSize: + required: true + type: string + + + aria.azure.datatypes.ImageReference: + properties: + publisher: + required: true + type: string + offer: + required: true + type: string + sku: + required: true + type: string + version: + required: true + type: string + + + aria.azure.datatypes.StorageProfile: + properties: + imageReference: + required: true + type: aria.azure.datatypes.ImageReference + + + + + aria.azure.datatypes.PublicKey: + properties: + keydata: + required: true + type: string + path: + required: true + type: string + + aria.azure.datatypes.SSH: + properties: + publicKeys: + required: false + type: list + entry_schema: aria.azure.datatypes.PublicKey + + + aria.azure.datatypes.LinuxConfiguration: + properties: + ssh: + required: false + type: aria.azure.datatypes.SSH + disablePasswordAuthentication: + required: false + default: true + type: boolean + + + aria.azure.datatypes.OSProfile: + properties: + computerName: + required: true + type: string + adminUserName: + required: true + type: string + adminPassword: + required: true + type: string + linuxConfiguration: + required: false + type: aria.azure.datatypes.LinuxConfiguration + + + + aria.azure.datatypes.VirtualMachineConfig: + description: > + https://msdn.microsoft.com/en-us/library/azure/mt163591.aspx + properties: + hardwareProfile: + required: true + type: aria.azure.datatypes.HardwareProfile + storageProfile: + required: true + type: aria.azure.datatypes.StorageProfile + osProfile: + required: true + type: aria.azure.datatypes.OSProfile + + aria.azure.datatypes.LoadBalancerConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163574.aspx + properties: + frontendIPConfigurations: + required: false + type: string + backendAddressPools: + required: false + type: string + loadBalancingRules: + required: false + type: string + probes: + required: false + type: string + inboundNatRules: + required: false + type: string + + + + aria.azure.datatypes.LoadBalancerProbeConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163574.aspx + properties: + protocol: + type: string + default: Tcp + required: true + port: + type: integer + required: true + requestPath: + type: string + required: false + intervalInSeconds: + type: integer + default: 5 + required: true + numberOfProbes: + type: integer + default: 16 + required: true + + aria.azure.datatypes.LoadBalancerIncomingNATRuleConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163574.aspx + properties: + protocol: + type: string + default: Tcp + required: true + frontendPort: + type: integer + required: true + backendPort: + type: integer + required: true + + + aria.azure.datatypes.LoadBalancerRuleConfig: + description: > + See https://msdn.microsoft.com/en-us/library/mt163574.aspx + properties: + protocol: + type: string + default: Tcp + required: true + frontendPort: + type: integer + required: true + backendPort: + type: integer + required: true + enableFloatingIP: + type: boolean + required: false + default: false + idleTimeoutInMinutes: + type: integer + required: false + default: 5 + loadDistribution: + type: string + required: false + default: Default + + + + + +interface_types: + + aria.azure.interfaces.validation: + derived_from: tosca.interfaces.Root + creation: + description: >- + creation operation for the openstack validation interface + deletion: + description: >- + deletion operation for the openstack validation interface + aria.azure.interfaces.network: + derived_from: tosca.interfaces.Root + preconfigure: + establish: + unlink: + +node_types: + + aria.azure.nodes.ResourceGroup: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. Resource group name must be no longer than + 80 characters long. It can contain only alphanumeric characters, + dash, underscore, opening parenthesis, closing parenthesis, + and period. The name cannot end with a period. + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.resourcegroup.create + delete: cloudify-azure-plugin > cloudify_azure.resources.resourcegroup.delete + + + + + + + + aria.azure.nodes.storage.StorageAccount: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. Storage account name must be between + 3 and 24 characters in length and use numbers and lower-case + letters only. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.StorageAccountConfig + required: true + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.storage.storageaccount.create + delete: cloudify-azure-plugin > cloudify_azure.resources.storage.storageaccount.delete + requirements: + - resource_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.ResourceGroup + relationship: cloudify.azure.relationships.contained_in_resource_group + occurrences: [ 0, UNBOUNDED ] + + + + aria.azure.nodes.storage.DataDisk: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource (include any extension, such as .vhd). + Can be up to 80 characters in length and + contain lowercase letters, numbers, ".", and "_". Must start + with a number or lowercase letter and cannot end with + either "_" or "." + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.DataDiskConfig + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.storage.disk.create_data_disk + delete: cloudify-azure-plugin > cloudify_azure.resources.storage.disk.delete_data_disk + requirements: + - storage_account: + capability: tosca.capabilities.Node + node: aria.azure.nodes.storage.StorageAccount + relationship: cloudify.azure.relationships.contained_in_storage_account + occurrences: [ 0, UNBOUNDED ] + + aria.azure.nodes.storage.FileShare: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. Can be up to 63 characters in length and + contain lowercase letters, numbers, and dashes. Must start + with a number or lowercase letter and cannot contain + two consecutive dashes. + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.FileShareConfig + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.storage.file.create_file_share + + + + + aria.azure.nodes.network.VirtualNetwork: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.VirtualNetworkConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.virtualnetwork.create + delete: cloudify-azure-plugin > cloudify_azure.resources.network.virtualnetwork.delete + requirements: + - resource_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.ResourceGroup + relationship: cloudify.azure.relationships.contained_in_resource_group + occurrences: [ 0, UNBOUNDED ] + - storage_account: + capability: tosca.capabilities.Node + node: aria.azure.nodes.storage.StorageAccount + relationship: cloudify.azure.relationships.virtual_network_depends_on_storage + occurrences: [ 0, UNBOUNDED ] + + + + aria.azure.nodes.network.NetworkSecurityGroup: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.NetworkSecurityGroupConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.networksecuritygroup.create + delete: cloudify-azure-plugin > cloudify_azure.resources.network.networksecuritygroup.delete + requirements: + - resource_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.ResourceGroup + relationship: cloudify.azure.relationships.contained_in_resource_group + occurrences: [ 0, UNBOUNDED ] + + + + aria.azure.nodes.network.NetworkSecurityRule: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + network_security_group_name: + type: string + description: > + Name of the Network Security Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Network Security Groupnode) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.NetworkSecurityRuleConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.networksecurityrule.create + delete: cloudify-azure-plugin > cloudify_azure.resources.network.networksecurityrule.delete + requirements: + - resource_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.ResourceGroup + relationship: cloudify.azure.relationships.contained_in_resource_group + occurrences: [ 0, UNBOUNDED ] + - network_security_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.NetworkSecurityGroup + relationship: cloudify.azure.relationships.nic_connected_to_network_security_group + occurrences: [ 0, UNBOUNDED ] + + + + aria.azure.nodes.network.Subnet: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + virtual_network_name: + type: string + description: > + Name of the Virtual Network that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Virtual Network node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.SubnetConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.subnet.create + delete: cloudify-azure-plugin > cloudify_azure.resources.network.subnet.delete + requirements: + - virtual_network: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.VirtualNetwork + relationship: cloudify.azure.relationships.contained_in_virtual_network + occurrences: [ 0, UNBOUNDED ] + - subnet_dependency: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.Subnet + relationship: cloudify.azure.relationships.depends_on_subnet + occurrences: [ 0, UNBOUNDED ] + + + + aria.azure.nodes.network.RouteTable: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.RouteTableConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.routetable.create + delete: cloudify-azure-plugin > cloudify_azure.resources.network.routetable.delete + requirements: + - virtual_subnet: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.Subnet + relationship: cloudify.azure.relationships.route_table_attached_to_subnet + occurrences: [ 0, UNBOUNDED ] + + aria.azure.nodes.network.Route: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + route_table_name: + type: string + description: > + Name of the Network Security Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Virtual Network node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.RouteConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.route.create + delete: cloudify-azure-plugin > cloudify_azure.resources.network.route.delete + requirements: + - route_table: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.RouteTable + relationship: cloudify.azure.relationships.depends_on_route_table + occurrences: [ 0, UNBOUNDED ] + + + aria.azure.nodes.network.NetworkInterfaceCard: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + primary: + description: > + When using multiple Network Interfaces, a primary must be set + required: false + default: false + type: boolean + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.NetworkInterfaceCardConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.networkinterfacecard.create + configure: cloudify-azure-plugin > cloudify_azure.resources.network.networkinterfacecard.configure + delete: cloudify-azure-plugin > cloudify_azure.resources.network.networkinterfacecard.delete + requirements: + - resource_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.ResourceGroup + relationship: cloudify.azure.relationships.contained_in_resource_group + occurrences: [ 0, UNBOUNDED ] + - ip_config: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.IPConfiguration + relationship: cloudify.azure.relationships.nic_connected_to_ip_configuration + occurrences: [ 0, UNBOUNDED ] + - security_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.NetworkSecurityGroup + relationship: cloudify.azure.relationships.nic_connected_to_network_security_group + occurrences: [ 0, UNBOUNDED ] + + + + aria.azure.nodes.network.IPConfiguration: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.IPConfigurationConfig + required: true + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + requirements: + - subnet: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.Subnet + relationship: cloudify.azure.relationships.ip_configuration_connected_to_subnet + occurrences: [ 0, UNBOUNDED ] + - ipaddress: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.PublicIPAddress + relationship: cloudify.azure.relationships.ip_configuration_connected_to_public_ip + occurrences: [ 0, UNBOUNDED ] + occurrences: [ 0, UNBOUNDED ] + + aria.azure.nodes.network.PublicIPAddress: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.PublicIPAddressConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.publicipaddress.create + delete: cloudify-azure-plugin > cloudify_azure.resources.network.publicipaddress.delete + requirements: + - resource_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.ResourceGroup + relationship: cloudify.azure.relationships.contained_in_resource_group + occurrences: [ 0, UNBOUNDED ] + + aria.azure.nodes.compute.AvailabilitySet: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.AvailabilitySetConfig + required: true + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.compute.availabilityset.create + delete: cloudify-azure-plugin > cloudify_azure.resources.compute.availabilityset.delete + + + aria.azure.nodes.compute.VirtualMachine: + derived_from: tosca.nodes.Compute + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + use_public_ip: + type: boolean + description: > + Tells the deployment to use the public IP (if available) of the resource + for Cloudify Agent connections + default: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + plan: + description: > + Specifies information about the marketplace image used to create the virtual + machine. This element is only used for marketplace images. + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.VirtualMachineConfig + required: true + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + ip: + description: | + Property specifying the IP address of the resource to + use for the agent installer. + type: string + required: false + os_family: + description: | + Property specifying what type of operating system family + this compute node will run. + default: windows + type: string + agent_config: + type: aria.azure.datatypes.AgentConfig + default: + install_method: remote + port: 5985 + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.compute.virtualmachine.create +# configure: +# implementation: cloudify-azure-plugin > cloudify_azure.resources.compute.virtualmachine.configure +# inputs: +# command_to_execute: +# description: > +# This is the command that the CustomScriptExtension extension will +# execute. The file_uris below will be downloaded and this property +# should specify a command to start the execution of one of them. +# default: powershell -ExecutionPolicy Unrestricted -file ps_enable_winrm_http.ps1 +# file_uris: +# default: +# - https://raw.githubusercontent.com/cloudify-cosmo/cloudify-azure-plugin/1.4/scripts/ps_enable_winrm_http.ps1 + delete: cloudify-azure-plugin > cloudify_azure.resources.compute.virtualmachine.delete + requirements: + - resource_group: + capability: tosca.capabilities.Node + node: aria.azure.nodes.ResourceGroup + relationship: cloudify.azure.relationships.contained_in_resource_group + occurrences: [ 0, UNBOUNDED ] + - nic: + capability: tosca.capabilities.Node + node: aria.azure.nodes.network.NetworkInterfaceCard + relationship: cloudify.azure.relationships.connected_to_nic + occurrences: [ 0, UNBOUNDED ] + - storage_account: + capability: tosca.capabilities.Node + node: aria.azure.nodes.storage.StorageAccount + relationship: cloudify.azure.relationships.connected_to_storage_account + - data_disk: + capability: tosca.capabilities.Node + node: aria.azure.nodes.storage.DataDisk + relationship: cloudify.azure.relationships.vm_connected_to_datadisk + occurrences: [ 0, UNBOUNDED ] + + + + aria.azure.nodes.network.LoadBalancer: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.LoadBalancerConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.create + configure: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.configure + delete: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.delete + + + + + aria.azure.nodes.network.LoadBalancer.BackendAddressPool: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + load_balancer_name: + type: string + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.create_backend_pool + delete: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.delete_backend_pool + + + + aria.azure.nodes.network.LoadBalancer.Probe: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + load_balancer_name: + type: string + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.LoadBalancerProbeConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.create_probe + delete: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.delete_probe + + + aria.azure.nodes.network.LoadBalancer.IncomingNATRule: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + load_balancer_name: + type: string + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.LoadBalancerIncomingNATRuleConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.create_incoming_nat_rule + delete: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.delete_incoming_nat_rule + + + + aria.azure.nodes.network.LoadBalancer.Rule: + derived_from: tosca.nodes.Root + properties: + name: + type: string + description: > + Name for the resource. + required: false + resource_group_name: + type: string + description: > + Name of the Resource Group that the existing resource belongs to + (this is only useful when not using a relationship between a resource + node and a Resource Group node) + required: false + load_balancer_name: + type: string + required: false + location: + type: string + description: > + Specifies the supported Azure location for the resource + required: false + tags: + description: > + Specifies a dictionary of one or more name and value pairs that describe a tag + required: false + type: string + resource_config: + description: > + A dictionary of values to pass as properties when creating the resource + type: aria.azure.datatypes.LoadBalancerRuleConfig + required: false + use_external_resource: + description: > + Indicate whether the resource exists or if Cloudify should create the resource + type: boolean + default: false + required: true + retry_after: + description: > + Overrides the Azure-specified "retry_after" response. This property + will set the number of seconds for each task retry interval (in the + case of iteratively checking the status of an asynchronous operation) + type: integer + required: false + azure_config: + description: > + A dictionary of values to pass to authenticate with the Azure API + type: aria.azure.datatypes.Config + required: false + interfaces: + Standard: + create: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.create_rule + delete: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.delete_rule + + + + + +relationship_types: + cloudify.azure.relationships.contained_in_resource_group: + derived_from: tosca.relationships.HostedOn + + cloudify.azure.relationships.contained_in_storage_account: + derived_from: tosca.relationships.HostedOn + + cloudify.azure.relationships.contained_in_virtual_network: + derived_from: tosca.relationships.HostedOn + + cloudify.azure.relationships.contained_in_network_security_group: + derived_from: tosca.relationships.HostedOn + + cloudify.azure.relationships.contained_in_route_table: + derived_from: tosca.relationships.HostedOn + + cloudify.azure.relationships.contained_in_load_balancer: + derived_from: tosca.relationships.HostedOn + + cloudify.azure.relationships.depends_on_route_table: + derived_from: tosca.relationships.DependsOn + + cloudify.azure.relationships.depends_on_subnet: + derived_from: tosca.relationships.DependsOn + + cloudify.azure.relationships.virtual_network_depends_on_storage: + derived_from: tosca.relationships.DependsOn + + cloudify.azure.relationships.network_security_group_attached_to_subnet: + derived_from: tosca.relationships.ConnectsTo + interfaces: + Configure: + add_source: cloudify-azure-plugin > cloudify_azure.resources.network.subnet.attach_network_security_group + remove_source: cloudify-azure-plugin > cloudify_azure.resources.network.subnet.detach_network_security_group + + cloudify.azure.relationships.route_table_attached_to_subnet: + derived_from: tosca.relationships.ConnectsTo + interfaces: + Configure: + add_source: cloudify-azure-plugin > cloudify_azure.resources.network.subnet.attach_route_table + remove_source: cloudify-azure-plugin > cloudify_azure.resources.network.subnet.detach_route_table + + cloudify.azure.relationships.nic_connected_to_network_security_group: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.nic_connected_to_ip_configuration: + derived_from: tosca.relationships.ConnectsTo + interfaces: + Configure: + pre_configure_source: cloudify-azure-plugin > cloudify_azure.resources.network.networkinterfacecard.attach_ip_configuration + + cloudify.azure.relationships.lb_connected_to_ip_configuration: + derived_from: tosca.relationships.ConnectsTo + interfaces: + Configure: + preconfigure: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.attach_ip_configuration + + cloudify.azure.relationships.ip_configuration_connected_to_subnet: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.ip_configuration_connected_to_public_ip: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.connected_to_storage_account: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.connected_to_data_disk: + derived_from: tosca.relationships.ConnectsTo + interfaces: + Configure: + add_target: cloudify-azure-plugin > cloudify_azure.resources.compute.virtualmachine.attach_disk + remove_target: cloudify-azure-plugin > cloudify_azure.resources.compute.virtualmachine.detach_disk + + + cloudify.azure.relationships.connected_to_nic: + derived_from: tosca.relationships.ConnectsTo + + + cloudify.azure.relationships.connected_to_availability_set: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.connected_to_ip_configuration: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.connected_to_lb_be_pool: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.connected_to_lb_probe: + derived_from: tosca.relationships.ConnectsTo + + cloudify.azure.relationships.vmx_contained_in_vm: + derived_from: tosca.relationships.HostedOn + + cloudify.azure.relationships.nic_connected_to_lb_be_pool: + derived_from: tosca.relationships.ConnectsTo + interfaces: + Configure: + add_target: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.attach_nic_to_backend_pool + remove_target: cloudify-azure-plugin > cloudify_azure.resources.network.loadbalancer.detach_nic_from_backend_pool + + cloudify.azure.relationships.vm_connected_to_datadisk: + derived_from: tosca.relationships.ConnectsTo + interfaces: + Configure: + add_target: + implementation: cloudify-azure-plugin > cloudify_azure.resources.compute.virtualmachine.attach_data_disk + inputs: + lun: + description: > + Specifies the logical unit number of the data disk in the VM + default: 0 + required: true + type: integer + remove_target: cloudify-azure-plugin > cloudify_azure.resources.compute.virtualmachine.detach_data_disk + + + diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/artifacts.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/artifacts.yaml new file mode 100644 index 0000000..945622f --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/artifacts.yaml @@ -0,0 +1,121 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +artifact_types: + + tosca.artifacts.Root: + _extensions: + shorthand_name: Root # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.3.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_ARTIFACTS_ROOT' + description: >- + This is the default (root) TOSCA Artifact Type definition that all other TOSCA base Artifact Types derive from. + + tosca.artifacts.File: + _extensions: + shorthand_name: File + type_qualified_name: tosca:File + specification: tosca-simple-1.0 + specification_section: 5.3.2 + description: >- + This artifact type is used when an artifact definition needs to have its associated file simply treated as a file and no special handling/handlers are invoked (i.e., it is not treated as either an implementation or deployment artifact type). + derived_from: tosca.artifacts.Root + + # + # Deployments + # + + tosca.artifacts.Deployment: + _extensions: + shorthand_name: Deployment # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Deployment + specification: tosca-simple-1.0 + specification_section: 5.3.3.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_ARTIFACTS_DEPLOYMENT' + description: >- + This artifact type represents the parent type for all deployment artifacts in TOSCA. This class of artifacts typically + represents a binary packaging of an application or service that is used to install/create or deploy it as part of a node's + lifecycle. + derived_from: tosca.artifacts.Root + + tosca.artifacts.Deployment.Image: + _extensions: + shorthand_name: Deployment.Image + type_qualified_name: tosca:Deployment.Image + specification: tosca-simple-1.0 + specification_section: 5.3.3.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_ARTIFACTS_DEPLOYMENT_IMAGE' + description: >- + This artifact type represents a parent type for any "image" which is an opaque packaging of a TOSCA Node's deployment + (whether real or virtual) whose contents are typically already installed and pre-configured (i.e., "stateful") and prepared + to be run on a known target container. + derived_from: tosca.artifacts.Deployment + + tosca.artifacts.Deployment.Image.VM: + _extensions: + shorthand_name: Deployment.VM # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Deployment.VM + specification: tosca-simple-1.0 + specification_section: 5.3.3.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_ARTIFACTS_DEPLOY_IMAGE_VM' + description: >- + This artifact represents the parent type for all Virtual Machine (VM) image and container formatted deployment artifacts. + These images contain a stateful capture of a machine (e.g., server) including operating system and installed software along + with any configurations and can be run on another machine using a hypervisor which virtualizes typical server (i.e., + hardware) resources. + derived_from: tosca.artifacts.Deployment + + # + # Implementations + # + + tosca.artifacts.Implementation: + _extensions: + shorthand_name: Implementation # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Implementation + specification: tosca-simple-1.0 + specification_section: 5.3.4.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_ARTIFACTS_IMPLEMENTATION' + description: >- + This artifact type represents the parent type for all implementation artifacts in TOSCA. These artifacts are used to + implement operations of TOSCA interfaces either directly (e.g., scripts) or indirectly (e.g., config. files). + derived_from: tosca.artifacts.Root + + tosca.artifacts.Implementation.Bash: + _extensions: + shorthand_name: Implementation.Bash # ARIA NOTE: mistake in spec? shouldn't we have "Implementation." as prefix? + type_qualified_name: tosca:Implementation.Bash + specification: tosca-simple-1.0 + specification_section: 5.3.4.3 + description: >- + This artifact type represents a Bash script type that contains Bash commands that can be executed on the Unix Bash shell. + derived_from: tosca.artifacts.Implementation + mime_type: application/x-sh + file_ext: [ sh ] + + tosca.artifacts.Implementation.Python: + _extensions: + shorthand_name: Implementation.Python # ARIA NOTE: mistake in spec? shouldn't we have "Implementation." as prefix? + type_qualified_name: tosca:Implementation.Python + specification: tosca-simple-1.0 + specification_section: 5.3.4.4 + description: >- + This artifact type represents a Python file that contains Python language constructs that can be executed within a Python + interpreter. + derived_from: tosca.artifacts.Implementation + mime_type: application/x-python + file_ext: [ py ] diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/capabilities.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/capabilities.yaml new file mode 100644 index 0000000..66a4046 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/capabilities.yaml @@ -0,0 +1,322 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +capability_types: + + tosca.capabilities.Root: + _extensions: + shorthand_name: Root # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.4.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_ROOT' + description: >- + This is the default (root) TOSCA Capability Type definition that all other TOSCA Capability Types derive from. + + tosca.capabilities.Node: + _extensions: + shorthand_name: Node + type_qualified_name: tosca:Node + specification: tosca-simple-1.0 + specification_section: 5.4.2 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_NODE' + role: feature + description: >- + The Node capability indicates the base capabilities of a TOSCA Node Type. + derived_from: tosca.capabilities.Root + + tosca.capabilities.Container: + _extensions: + shorthand_name: Container + type_qualified_name: tosca:Container + specification: tosca-simple-1.0 + specification_section: 5.4.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_CONTAINER' + role: host + description: >- + The Container capability, when included on a Node Type or Template definition, indicates that the node can act as a container + for (or a host for) one or more other declared Node Types. + derived_from: tosca.capabilities.Root + properties: + num_cpus: + description: >- + Number of (actual or virtual) CPUs associated with the Compute node. + type: integer + constraints: + - greater_or_equal: 1 + required: false + cpu_frequency: + description: >- + Specifies the operating frequency of CPU's core. This property expresses the expected frequency of one (1) CPU as + provided by the property "num_cpus". + type: scalar-unit.frequency + constraints: + - greater_or_equal: 0.1 GHz + required: false + disk_size: + description: >- + Size of the local disk available to applications running on the Compute node (default unit is MB). + type: scalar-unit.size + constraints: + - greater_or_equal: 0 MB + required: false + mem_size: + description: >- + Size of memory available to applications running on the Compute node (default unit is MB). + type: scalar-unit.size + constraints: + - greater_or_equal: 0 MB + required: false + + tosca.capabilities.Attachment: + _extensions: + shorthand_name: Attachment + type_qualified_name: tosca:Attachment + specification: tosca-simple-1.0 + specification_section: 5.4.8 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_ATTACHMENT' + description: >- + This is the default TOSCA type that should be used or extended to define an attachment capability of a (logical) + infrastructure device node (e.g., BlockStorage node). + derived_from: tosca.capabilities.Root + + tosca.capabilities.OperatingSystem: + _extensions: + shorthand_name: OperatingSystem + type_qualified_name: tosca:OperatingSystem + specification: tosca-simple-1.0 + specification_section: 5.4.9 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_OPSYS' + description: >- + This is the default TOSCA type that should be used to express an Operating System capability for a node. + derived_from: tosca.capabilities.Root + properties: + architecture: + description: >- + The Operating System (OS) architecture. Examples of valid values include: x86_32, x86_64, etc. + type: string + required: false + type: + description: >- + The Operating System (OS) type. Examples of valid values include: linux, aix, mac, windows, etc. + type: string + required: false + distribution: + description: >- + The Operating System (OS) distribution. Examples of valid values for a "type" of "Linux" would include: debian, fedora, + rhel and ubuntu. + type: string + required: false + version: + description: >- + The Operating System version. + type: version + required: false + + tosca.capabilities.Scalable: + _extensions: + shorthand_name: Scalable + type_qualified_name: tosca:Scalable + specification: tosca-simple-1.0 + specification_section: 5.4.10 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_SCALABLE' + role: scaling + description: >- + This is the default TOSCA type that should be used to express a scalability capability for a node. + derived_from: tosca.capabilities.Root + properties: + min_instances: + description: >- + This property is used to indicate the minimum number of instances that should be created for the associated TOSCA Node + Template by a TOSCA orchestrator. + type: integer + default: 1 + max_instances: + description: >- + This property is used to indicate the maximum number of instances that should be created for the associated TOSCA Node + Template by a TOSCA orchestrator. + type: integer + default: 1 + default_instances: + description: >- + An optional property that indicates the requested default number of instances that should be the starting number of + instances a TOSCA orchestrator should attempt to allocate. Note: The value for this property MUST be in the range between + the values set for "min_instances" and "max_instances" properties. + type: integer + required: false + + # + # Endpoints + # + + tosca.capabilities.Endpoint: + _extensions: + shorthand_name: Endpoint + type_qualified_name: tosca:Endpoint + specification: tosca-simple-1.0 + specification_section: 5.4.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_ENDPOINT' + description: >- + This is the default TOSCA type that should be used or extended to define a network endpoint capability. This includes the information to express a basic endpoint with a single port or a complex endpoint with multiple ports. By default the Endpoint is assumed to represent an address on a private network unless otherwise specified. + derived_from: tosca.capabilities.Root + properties: + protocol: + description: >- + The name of the protocol (i.e., the protocol prefix) that the endpoint accepts (any OSI Layer 4-7 protocols). Examples: + http, https, ftp, tcp, udp, etc. + type: string + default: tcp + required: true + port: + description: >- + The optional port of the endpoint. + type: tosca.datatypes.network.PortDef + required: false + secure: + description: >- + Requests for the endpoint to be secure and use credentials supplied on the ConnectsTo relationship. + type: boolean + default: false + required: false + url_path: + description: >- + The optional URL path of the endpoint's address if applicable for the protocol. + type: string + required: false + port_name: + description: >- + The optional name (or ID) of the network port this endpoint should be bound to. + type: string + required: false + network_name: + description: >- + The optional name (or ID) of the network this endpoint should be bound to. network_name: PRIVATE | PUBLIC | + <network_name> | <network_id>. + type: string + default: PRIVATE + required: false + initiator: + description: >- + The optional indicator of the direction of the connection. + type: string + constraints: + - valid_values: [ source, target, peer ] + default: source + required: false + ports: + description: >- + The optional map of ports the Endpoint supports (if more than one). + type: map + entry_schema: + type: tosca.datatypes.network.PortSpec + constraints: + - min_length: 1 + required: false + attributes: + ip_address: + description: >- + Note: This is the IP address as propagated up by the associated node's host (Compute) container. + type: string + + tosca.capabilities.Endpoint.Public: + _extensions: + shorthand_name: Endpoint.Public + type_qualified_name: tosca:Endpoint.Public + specification: tosca-simple-1.0 + specification_section: 5.4.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_ENDPOINT_PUBLIC' + description: >- + This capability represents a public endpoint which is accessible to the general internet (and its public IP address ranges). + + This public endpoint capability also can be used to create a floating (IP) address that the underlying network assigns from a + pool allocated from the application's underlying public network. This floating address is managed by the underlying network + such that can be routed an application's private address and remains reliable to internet clients. + derived_from: tosca.capabilities.Endpoint + properties: + network_name: + type: string + constraints: + - equal: PUBLIC + default: PUBLIC + floating: + description: >- + Indicates that the public address should be allocated from a pool of floating IPs that are associated with the network. + type: boolean + default: false + status: experimental + dns_name: + description: >- + The optional name to register with DNS. + type: string + required: false + status: experimental + + tosca.capabilities.Endpoint.Admin: + _extensions: + shorthand_name: Endpoint.Admin + type_qualified_name: tosca:Endpoint.Admin + specification: tosca-simple-1.0 + specification_section: 5.4.6 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_ENDPOINT_ADMIN' + description: >- + This is the default TOSCA type that should be used or extended to define a specialized administrator endpoint capability. + derived_from: tosca.capabilities.Endpoint + properties: + secure: + description: >- + Requests for the endpoint to be secure and use credentials supplied on the ConnectsTo relationship. + type: boolean + constraints: + - equal: true + default: true + + tosca.capabilities.Endpoint.Database: + _extensions: + shorthand_name: Endpoint.Database + type_qualified_name: tosca:Endpoint.Database + specification: tosca-simple-1.0 + specification_section: 5.4.7 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_ENDPOINT_DATABASE' + description: >- + This is the default TOSCA type that should be used or extended to define a specialized database endpoint capability. + derived_from: tosca.capabilities.Endpoint + + # + # Network + # + + tosca.capabilities.network.Bindable: + _extensions: + shorthand_name: Bindable # ARIA NOTE: mistake in spec? has "network." as a prefix + type_qualified_name: tosca:Bindable + specification: tosca-simple-1.0 + specification_section: 5.4.11 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_NETWORK_BINDABLE' + description: >- + A node type that includes the Bindable capability indicates that it can be bound to a logical network association via a + network port. + derived_from: tosca.capabilities.Node + + tosca.capabilities.network.Linkable: + _extensions: + shorthand_name: Linkable + type_qualified_name: tosca:Linkable + specification: tosca-simple-1.0 + specification_section: 7.5.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_CAPABILITIES_NETWORK_LINKABLE' + description: >- + A node type that includes the Linkable capability indicates that it can be pointed by tosca.relationships.network.LinksTo + relationship type. + derived_from: tosca.capabilities.Node diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/data.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/data.yaml new file mode 100644 index 0000000..61d4186 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/data.yaml @@ -0,0 +1,268 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +data_types: + + # + # Primitive + # + + timestamp: + _extensions: + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_timestamp + + version: + _extensions: + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_version + type_qualified_name: tosca:version + specification: tosca-simple-1.0 + specification_section: 3.2.2 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_VERSION' + + range: + _extensions: + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_range + type_qualified_name: tosca:range + specification: tosca-simple-1.0 + specification_section: 3.2.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_RANGE' + + # + # With entry schema + # + + list: + _extensions: + use_entry_schema: true + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_list + type_qualified_name: tosca:list + specification: tosca-simple-1.0 + specification_section: 3.2.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_LIST' + + map: + _extensions: + use_entry_schema: true + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_map_value + type_qualified_name: tosca:map + specification: tosca-simple-1.0 + specification_section: 3.2.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_MAP' + + # + # Scalar + # + + scalar-unit.size: + _extensions: + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_scalar_unit_size + type_qualified_name: tosca:scalar-unit.size + specification: tosca-simple-1.0 + specification_section: 3.2.6.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_SCALAR_UNIT_SIZE' + + scalar-unit.time: + _extensions: + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_scalar_unit_time + type_qualified_name: tosca:scalar-unit.time + specification: tosca-simple-1.0 + specification_section: 3.2.6.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_SCALAR_UNIT_TIME' + + scalar-unit.frequency: + _extensions: + coerce_value: aria_extension_tosca.simple_v1_0.data_types.coerce_scalar_unit_frequency + type_qualified_name: tosca:scalar-unit.frequency + specification: tosca-simple-1.0 + specification_section: 3.2.6.6 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_SCALAR_UNIT_FREQUENCY' + + # + # Complex + # + + tosca.datatypes.Root: + _extensions: + shorthand_name: Root # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.2.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_DATA_ROOT' + description: >- + This is the default (root) TOSCA Root Type definition that all complex TOSCA Data Types derive from. + + tosca.datatypes.Credential: + _extensions: + shorthand_name: Credential + type_qualified_name: tosca:Credential + specification: tosca-simple-1.0 + specification_section: 5.2.2 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_DATA_CREDENTIAL' + description: >- + The Credential type is a complex TOSCA data Type used when describing authorization credentials used to access network + accessible resources. + derived_from: tosca.datatypes.Root + properties: + protocol: + description: >- + The optional protocol name. + type: string + required: false + token_type: + description: >- + The required token type. + type: string + default: password + token: + description: >- + The required token used as a credential for authorization or access to a networked resource. + type: string + required: false + keys: + description: >- + The optional list of protocol-specific keys or assertions. + type: map + entry_schema: + type: string + required: false + user: + description: >- + The optional user (name or ID) used for non-token based credentials. + type: string + required: false + + tosca.datatypes.network.NetworkInfo: + _extensions: + shorthand_name: NetworkInfo + type_qualified_name: tosca:NetworkInfo + specification: tosca-simple-1.0 + specification_section: 5.2.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_DATA_NETWORKINFO' + description: >- + The Network type is a complex TOSCA data type used to describe logical network information. + derived_from: tosca.datatypes.Root + properties: + network_name: + description: >- + The name of the logical network. e.g., "public", "private", "admin". etc. + type: string + required: false + network_id: + description: >- + The unique ID of for the network generated by the network provider. + type: string + required: false + addresses: + description: >- + The list of IP addresses assigned from the underlying network. + type: list + entry_schema: + type: string + required: false + + tosca.datatypes.network.PortInfo: + _extensions: + shorthand_name: PortInfo + type_qualified_name: tosca:PortInfo + specification: tosca-simple-1.0 + specification_section: 5.2.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_DATA_PORTINFO' + description: >- + The PortInfo type is a complex TOSCA data type used to describe network port information. + derived_from: tosca.datatypes.Root + properties: + port_name: + description: >- + The logical network port name. + type: string + required: false + port_id: + description: >- + The unique ID for the network port generated by the network provider. + type: string + required: false + network_id: + description: >- + The unique ID for the network. + type: string + required: false + mac_address: + description: >- + The unique media access control address (MAC address) assigned to the port. + type: string + required: false + addresses: + description: >- + The list of IP address(es) assigned to the port. + type: list + entry_schema: + type: string + required: false + + tosca.datatypes.network.PortDef: + _extensions: + shorthand_name: PortDef + type_qualified_name: tosca:PortDef + specification: tosca-simple-1.0 + specification_section: 5.2.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_DATA_PORTDEF' + description: >- + The PortDef type is a TOSCA data Type used to define a network port. + derived_from: integer # ARIA NOTE: we allow deriving from primitives + constraints: + - in_range: [ 1, 65535 ] + + tosca.datatypes.network.PortSpec: + _extensions: + shorthand_name: PortSpec + type_qualified_name: tosca:PortSpec + specification: tosca-simple-1.0 + specification_section: 5.2.6 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#TYPE_TOSCA_DATA_PORTSPEC' + description: >- + The PortSpec type is a complex TOSCA data Type used when describing port specifications for a network connection. + derived_from: tosca.datatypes.Root + properties: + protocol: + description: >- + The required protocol used on the port. + type: string + constraints: + - valid_values: [ udp, tcp, igmp ] + default: tcp + source: + description: >- + The optional source port. + type: tosca.datatypes.network.PortDef + required: false + source_range: + description: >- + The optional range for source port. + type: range + constraints: + - in_range: [ 1, 65535 ] + required: false + target: + description: >- + The optional target port. + type: tosca.datatypes.network.PortDef + required: false + target_range: + description: >- + The optional range for target port. + type: range + constraints: + - in_range: [ 1, 65535 ] + required: false diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/groups.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/groups.yaml new file mode 100644 index 0000000..66cc25f --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/groups.yaml @@ -0,0 +1,28 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +group_types: + + tosca.groups.Root: + _extensions: + shorthand_name: Root # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.9.1 + description: >- + This is the default (root) TOSCA Group Type definition that all other TOSCA base Group Types derive from. + interfaces: + Standard: + type: tosca.interfaces.node.lifecycle.Standard diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/interfaces.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/interfaces.yaml new file mode 100644 index 0000000..29cc8dd --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/interfaces.yaml @@ -0,0 +1,107 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +interface_types: + + tosca.interfaces.Root: + _extensions: + shorthand_name: Root # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.7.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Ref384391055' + description: >- + This is the default (root) TOSCA Interface Type definition that all other TOSCA Interface Types derive from. + + tosca.interfaces.node.lifecycle.Standard: + _extensions: + shorthand_name: Standard + type_qualified_name: tosca:Standard + specification: tosca-simple-1.0 + specification_section: 5.7.4 + description: >- + This lifecycle interface defines the essential, normative operations that TOSCA nodes may support. + derived_from: tosca.interfaces.Root + create: + description: >- + Standard lifecycle create operation. + configure: + description: >- + Standard lifecycle configure operation. + start: + description: >- + Standard lifecycle start operation. + stop: + description: >- + Standard lifecycle stop operation. + delete: + description: >- + Standard lifecycle delete operation. + + tosca.interfaces.relationship.Configure: + _extensions: + shorthand_name: Configure + type_qualified_name: tosca:Configure + specification: tosca-simple-1.0 + specification_section: 5.7.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_ITFC_RELATIONSHIP_CONFIGURE' + description: >- + The lifecycle interfaces define the essential, normative operations that each TOSCA Relationship Types may support. + derived_from: tosca.interfaces.Root + pre_configure_source: + description: >- + Operation to pre-configure the source endpoint. + _extensions: + relationship_edge: source + pre_configure_target: + description: >- + Operation to pre-configure the target endpoint. + _extensions: + relationship_edge: target + post_configure_source: + description: >- + Operation to post-configure the source endpoint. + _extensions: + relationship_edge: source + post_configure_target: + description: >- + Operation to post-configure the target endpoint. + _extensions: + relationship_edge: target + add_target: + description: >- + Operation to notify the source node of a target node being added via a relationship. + _extensions: + relationship_edge: source + add_source: + description: >- + Operation to notify the target node of a source node which is now available via a relationship. + _extensions: + relationship_edge: target + target_changed: + description: >- + Operation to notify source some property or attribute of the target changed + _extensions: + relationship_edge: source + remove_target: + description: >- + Operation to remove a target node. + _extensions: + relationship_edge: source + remove_source: + description: >- + Operation to remove the source node. + _extensions: + relationship_edge: target diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/nodes.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/nodes.yaml new file mode 100644 index 0000000..05963b7 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/nodes.yaml @@ -0,0 +1,525 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +node_types: + + tosca.nodes.Root: + _extensions: + shorthand_name: Root + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.8.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_ROOT' + description: >- + The TOSCA Root Node Type is the default type that all other TOSCA base Node Types derive from. This allows for all TOSCA nodes to have a consistent set of features for modeling and management (e.g., consistent definitions for requirements, capabilities and lifecycle interfaces). + attributes: + tosca_id: + description: >- + A unique identifier of the realized instance of a Node Template that derives from any TOSCA normative type. + type: string + tosca_name: + description: >- + This attribute reflects the name of the Node Template as defined in the TOSCA service template. This name is not unique + to the realized instance model of corresponding deployed application as each template in the model can result in one or + more instances (e.g., scaled) when orchestrated to a provider environment. + type: string + state: + description: >- + The state of the node instance. + type: string + default: initial + interfaces: + Standard: + type: tosca.interfaces.node.lifecycle.Standard + capabilities: + feature: + type: tosca.capabilities.Node + requirements: + - dependency: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: [ 0, UNBOUNDED ] + + tosca.nodes.Compute: + _extensions: + shorthand_name: Compute + type_qualified_name: tosca:Compute + specification: tosca-simple-1.0 + specification_section: 5.8.2 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_COMPUTE' + role: host + description: >- + The TOSCA Compute node represents one or more real or virtual processors of software applications or services along with + other essential local resources. Collectively, the resources the compute node represents can logically be viewed as a (real + or virtual) "server". + derived_from: tosca.nodes.Root + attributes: + private_address: + description: >- + The primary private IP address assigned by the cloud provider that applications may use to access the Compute node. + type: string + public_address: + description: >- + The primary public IP address assigned by the cloud provider that applications may use to access the Compute node. + type: string + networks: + description: >- + The list of logical networks assigned to the compute host instance and information about them. + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + description: >- + The list of logical ports assigned to the compute host instance and information about them. + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [ tosca.nodes.SoftwareComponent ] + binding: + type: tosca.capabilities.network.Bindable + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ 0, UNBOUNDED ] + + tosca.nodes.LoadBalancer: + _extensions: + shorthand_name: LoadBalancer + type_qualified_name: tosca:LoadBalancer + specification: tosca-simple-1.0 + specification_section: 5.8.12 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc379548332' + description: >- + The TOSCA Load Balancer node represents logical function that be used in conjunction with a Floating Address to distribute an + application's traffic (load) across a number of instances of the application (e.g., for a clustered or scaled application). + derived_from: tosca.nodes.Root + properties: + algorithm: + description: >- + No description in spec. + type: string + required: false + status: experimental + capabilities: + client: + description: >- + The Floating (IP) client's on the public network can connect to. + type: tosca.capabilities.Endpoint.Public + occurrences: [ 0, UNBOUNDED ] # ARIA NOTE: it seems unnecessary to specify this, as it is the implied default + requirements: + - application: + capability: tosca.capabilities.Endpoint + relationship: tosca.relationships.RoutesTo + occurrences: [ 0, UNBOUNDED ] + + # + # Software + # + + tosca.nodes.SoftwareComponent: + _extensions: + shorthand_name: SoftwareComponent + type_qualified_name: tosca:SoftwareComponent + specification: tosca-simple-1.0 + specification_section: 5.8.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_SOFTWARE_COMPONENT' + description: >- + The TOSCA SoftwareComponent node represents a generic software component that can be managed and run by a TOSCA Compute Node + Type. + derived_from: tosca.nodes.Root + properties: + component_version: + description: >- + The optional software component's version. + type: version + required: false + admin_credential: + description: >- + The optional credential that can be used to authenticate to the software component. + type: tosca.datatypes.Credential + required: false + requirements: + - host: + capability: tosca.capabilities.Container + node: tosca.nodes.Compute + relationship: tosca.relationships.HostedOn + + tosca.nodes.WebServer: + _extensions: + shorthand_name: WebServer + type_qualified_name: tosca:WebServer + specification: tosca-simple-1.0 + specification_section: 5.8.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_WEBSERVER' + description: >- + This TOSCA WebServer Node Type represents an abstract software component or service that is capable of hosting and providing + management operations for one or more WebApplication nodes. + derived_from: tosca.nodes.SoftwareComponent + capabilities: + data_endpoint: + type: tosca.capabilities.Endpoint + admin_endpoint: + type: tosca.capabilities.Endpoint.Admin + host: + type: tosca.capabilities.Container + valid_source_types: [ tosca.nodes.WebApplication ] + + tosca.nodes.WebApplication: + _extensions: + shorthand_name: WebApplication + type_qualified_name: tosca:WebApplication + specification: tosca-simple-1.0 + specification_section: 5.8.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_WEBAPPLICATION' + description: >- + The TOSCA WebApplication node represents a software application that can be managed and run by a TOSCA WebServer node. + Specific types of web applications such as Java, etc. could be derived from this type. + derived_from: tosca.nodes.SoftwareComponent # ARIA NOTE: the spec says tosca.nodes.Root + properties: + context_root: + description: >- + The web application's context root which designates the application's URL path within the web server it is hosted on. + type: string + required: false + capabilities: + app_endpoint: + type: tosca.capabilities.Endpoint + requirements: + - host: + capability: tosca.capabilities.Container + node: tosca.nodes.WebServer + relationship: tosca.relationships.HostedOn + + tosca.nodes.DBMS: + _extensions: + shorthand_name: DBMS # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:DBMS + specification: tosca-simple-1.0 + specification_section: 5.8.6 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_DBMS' + description: >- + The TOSCA DBMS node represents a typical relational, SQL Database Management System software component or service. + derived_from: tosca.nodes.SoftwareComponent + properties: + root_password: + description: >- + The optional root password for the DBMS server. + type: string + required: false + port: + description: >- + The DBMS server's port. + type: integer + required: false + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [ tosca.nodes.Database ] + + tosca.nodes.Database: + _extensions: + shorthand_name: Database + type_qualified_name: tosca:Database + specification: tosca-simple-1.0 + specification_section: 5.8.7 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_DATABASE' + description: >- + The TOSCA Database node represents a logical database that can be managed and hosted by a TOSCA DBMS node. + derived_from: tosca.nodes.Root # ARIA NOTE: it's *not* a SoftwareComponent + properties: + name: + description: >- + The logical database Name. + type: string + port: + description: >- + The port the database service will use to listen for incoming data and requests. + type: integer + required: false + user: + description: >- + The special user account used for database administration. + type: string + required: false + password: + description: >- + The password associated with the user account provided in the 'user' property. + type: string + required: false + capabilities: + database_endpoint: + type: tosca.capabilities.Endpoint.Database + requirements: + - host: + capability: tosca.capabilities.Container + node: tosca.nodes.DBMS + relationship: tosca.relationships.HostedOn + + # + # Container + # + + tosca.nodes.Container.Runtime: + _extensions: + shorthand_name: Container.Runtime + type_qualified_name: tosca:Container.Runtime + specification: tosca-simple-1.0 + specification_section: 5.8.10 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_CONTAINER_RUNTIME' + description: >- + The TOSCA Container Runtime node represents operating system-level virtualization technology used to run multiple application + services on a single Compute host. + derived_from: tosca.nodes.SoftwareComponent + capabilities: + host: + type: tosca.capabilities.Container + scalable: + type: tosca.capabilities.Scalable + + tosca.nodes.Container.Application: + _extensions: + shorthand_name: Container.Application + type_qualified_name: tosca:Container.Application + specification: tosca-simple-1.0 + specification_section: 5.8.11 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_CONTAINER_APP' + description: >- + The TOSCA Container Application node represents an application that requires Container-level virtualization technology. + derived_from: tosca.nodes.Root + requirements: + - host: + capability: tosca.capabilities.Container + # ARIA NOTE: seems a mistake in the spec + #node: tosca.nodes.Container + relationship: tosca.relationships.HostedOn + + # + # Storage + # + + tosca.nodes.ObjectStorage: + _extensions: + shorthand_name: ObjectStorage + type_qualified_name: tosca:ObjectStorage + specification: tosca-simple-1.0 + specification_section: 5.8.8 + description: >- + The TOSCA ObjectStorage node represents storage that provides the ability to store data as objects (or BLOBs of data) without + consideration for the underlying filesystem or devices. + derived_from: tosca.nodes.Root + properties: + name: + description: >- + The logical name of the object store (or container). + type: string + size: + description: >- + The requested initial storage size (default unit is in Gigabytes). + type: scalar-unit.size + constraints: + - greater_or_equal: 0 GB + required: false + maxsize: + description: >- + The requested maximum storage size (default unit is in Gigabytes). + type: scalar-unit.size + constraints: + - greater_or_equal: 0 GB + required: false + capabilities: + storage_endpoint: + type: tosca.capabilities.Endpoint + + tosca.nodes.BlockStorage: + _extensions: + shorthand_name: BlockStorage + type_qualified_name: tosca:BlockStorage + specification: tosca-simple-1.0 + specification_section: 5.8.9 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_NODES_BLOCK_STORAGE' + description: >- + derived_from: tosca.nodes.Root + properties: + size: + description: >- + The requested storage size (default unit is MB). + type: scalar-unit.size + constraints: + - greater_or_equal: 1 MB + volume_id: + description: >- + ID of an existing volume (that is in the accessible scope of the requesting application). + type: string + required: false + snapshot_id: + description: >- + Some identifier that represents an existing snapshot that should be used when creating the block storage (volume). + type: string + required: false + capabilities: + attachment: + type: tosca.capabilities.Attachment + + # + # Network + # + + tosca.nodes.network.Network: + _extensions: + shorthand_name: Network + type_qualified_name: tosca:Network + specification: tosca-simple-1.0 + specification_section: 7.5.1 + description: >- + The TOSCA Network node represents a simple, logical network service. + derived_from: tosca.nodes.Root + properties: + ip_version: + description: >- + The IP version of the requested network. + type: integer + constraints: + - valid_values: [ 4, 6 ] + default: 4 + required: false + cidr: + description: >- + The cidr block of the requested network. + type: string + required: false + start_ip: + description: >- + The IP address to be used as the 1st one in a pool of addresses derived from the cidr block full IP range. + type: string + required: false + end_ip: + description: >- + The IP address to be used as the last one in a pool of addresses derived from the cidr block full IP range. + type: string + required: false + gateway_ip: + description: >- + The gateway IP address. + type: string + required: false + network_name: + description: >- + An Identifier that represents an existing Network instance in the underlying cloud infrastructure - OR - be used as the + name of the new created network. + type: string + required: false + network_id: + description: >- + An Identifier that represents an existing Network instance in the underlying cloud infrastructure. This property is + mutually exclusive with all other properties except network_name. + type: string + required: false + segmentation_id: + description: >- + A segmentation identifier in the underlying cloud infrastructure (e.g., VLAN id, GRE tunnel id). If the segmentation_id + is specified, the network_type or physical_network properties should be provided as well. + type: string + required: false + network_type: + description: >- + Optionally, specifies the nature of the physical network in the underlying cloud infrastructure. Examples are flat, vlan, + gre or vxlan. For flat and vlan types, physical_network should be provided too. + type: string + required: false + physical_network: + description: >- + Optionally, identifies the physical network on top of which the network is implemented, e.g. physnet1. This property is + required if network_type is flat or vlan. + type: string + required: false + dhcp_enabled: + description: >- + Indicates the TOSCA container to create a virtual network instance with or without a DHCP service. + type: boolean + default: true + required: false + capabilities: + link: + type: tosca.capabilities.network.Linkable + + tosca.nodes.network.Port: + _extensions: + shorthand_name: Port + type_qualified_name: tosca:Port + specification: tosca-simple-1.0 + specification_section: 7.5.2 + description: >- + The TOSCA Port node represents a logical entity that associates between Compute and Network normative types. + + The Port node type effectively represents a single virtual NIC on the Compute node instance. + derived_from: tosca.nodes.Root + properties: + ip_address: + description: >- + Allow the user to set a fixed IP address. Note that this address is a request to the provider which they will attempt to + fulfill but may not be able to dependent on the network the port is associated with. + type: string + required: false + order: + description: >- + The order of the NIC on the compute instance (e.g. eth2). Note: when binding more than one port to a single compute (aka + multi vNICs) and ordering is desired, it is *mandatory* that all ports will be set with an order value and. The order + values must represent a positive, arithmetic progression that starts with 0 (e.g. 0, 1, 2, ..., n). + type: integer + constraints: + - greater_or_equal: 0 + default: 0 + required: false + is_default: + description: >- + Set is_default=true to apply a default gateway route on the running compute instance to the associated network gateway. + Only one port that is associated to single compute node can set as default=true. + type: boolean + default: false + required: false + ip_range_start: + description: >- + Defines the starting IP of a range to be allocated for the compute instances that are associated by this Port. Without + setting this property the IP allocation is done from the entire CIDR block of the network. + type: string + required: false + ip_range_end: + description: >- + Defines the ending IP of a range to be allocated for the compute instances that are associated by this Port. Without + setting this property the IP allocation is done from the entire CIDR block of the network. + type: string + required: false + attributes: + ip_address: + description: >- + The IP address would be assigned to the associated compute instance. + type: string + requirements: + - link: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + - binding: + capability: tosca.capabilities.network.Bindable + relationship: tosca.relationships.network.BindsTo diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/policies.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/policies.yaml new file mode 100644 index 0000000..7b35bb9 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/policies.yaml @@ -0,0 +1,71 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +policy_types: + + tosca.policies.Root: + _extensions: + shorthand_name: Root # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.10.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_POLICIES_ROOT' + description: >- + This is the default (root) TOSCA Policy Type definition that all other TOSCA base Policy Types derive from. + + tosca.policies.Placement: + _extensions: + shorthand_name: Placement # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Placement + specification: tosca-simple-1.0 + specification_section: 5.10.2 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_POLICIES_PLACEMENT' + description: >- + This is the default (root) TOSCA Policy Type definition that is used to govern placement of TOSCA nodes or groups of nodes. + derived_from: tosca.policies.Root + + tosca.policies.Scaling: + _extensions: + shorthand_name: Scaling # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Scaling + specification: tosca-simple-1.0 + specification_section: 5.10.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_POLICIES_SCALING' + description: >- + This is the default (root) TOSCA Policy Type definition that is used to govern scaling of TOSCA nodes or groups of nodes. + derived_from: tosca.policies.Root + + tosca.policies.Update: + _extensions: + shorthand_name: Update # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Update + specification: tosca-simple-1.0 + specification_section: 5.10.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_POLICIES_UPDATE' + description: >- + This is the default (root) TOSCA Policy Type definition that is used to govern update of TOSCA nodes or groups of nodes. + derived_from: tosca.policies.Root + + tosca.policies.Performance: + _extensions: + shorthand_name: Performance # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Performance + specification: tosca-simple-1.0 + specification_section: 5.10.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_POLICIES_PERFORMANCE' + description: >- + This is the default (root) TOSCA Policy Type definition that is used to declare performance requirements for TOSCA nodes or + groups of nodes. + derived_from: tosca.policies.Root diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/relationships.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/relationships.yaml new file mode 100644 index 0000000..9f2c32c --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/relationships.yaml @@ -0,0 +1,158 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +relationship_types: + + tosca.relationships.Root: + _extensions: + shorthand_name: Root # ARIA NOTE: omitted in the spec + type_qualified_name: tosca:Root + specification: tosca-simple-1.0 + specification_section: 5.6.1 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_RELATIONSHIPS_ROOT' + description: >- + This is the default (root) TOSCA Relationship Type definition that all other TOSCA Relationship Types derive from. + attributes: + tosca_id: + description: >- + A unique identifier of the realized instance of a Relationship Template that derives from any TOSCA normative type. + type: string + tosca_name: + description: >- + This attribute reflects the name of the Relationship Template as defined in the TOSCA service template. This name is not + unique to the realized instance model of corresponding deployed application as each template in the model can result in + one or more instances (e.g., scaled) when orchestrated to a provider environment. + type: string + state: + description: >- + The state of the relationship instance. + type: string + default: initial + interfaces: + Configure: + type: tosca.interfaces.relationship.Configure + + tosca.relationships.DependsOn: + _extensions: + shorthand_name: DependsOn + type_qualified_name: tosca:DependsOn + specification: tosca-simple-1.0 + specification_section: 5.6.2 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_RELATIONSHIPS_DEPENDSON' + description: >- + This type represents a general dependency relationship between two nodes. + derived_from: tosca.relationships.Root + valid_target_types: [ tosca.capabilities.Node ] + + tosca.relationships.HostedOn: + _extensions: + shorthand_name: HostedOn + type_qualified_name: tosca:HostedOn + specification: tosca-simple-1.0 + specification_section: 5.6.3 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_RELATIONSHIPS_HOSTEDON' + description: >- + This type represents a hosting relationship between two nodes. + derived_from: tosca.relationships.Root + valid_target_types: [ tosca.capabilities.Container ] + + tosca.relationships.ConnectsTo: + _extensions: + shorthand_name: ConnectsTo + type_qualified_name: tosca:ConnectsTo + specification: tosca-simple-1.0 + specification_section: 5.6.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_RELATIONSHIPS_CONNECTSTO' + description: >- + This type represents a network connection relationship between two nodes. + derived_from: tosca.relationships.Root + valid_target_types: [ tosca.capabilities.Endpoint ] + properties: + credential: + type: tosca.datatypes.Credential + required: false + + tosca.relationships.AttachesTo: + _extensions: + shorthand_name: AttachesTo + type_qualified_name: tosca:AttachesTo + specification: tosca-simple-1.0 + specification_section: 5.6.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_RELATIONSHIPS_ATTACHTO' + description: >- + This type represents an attachment relationship between two nodes. For example, an AttachesTo relationship type would be used + for attaching a storage node to a Compute node. + derived_from: tosca.relationships.Root + valid_target_types: [ tosca.capabilities.Attachment ] + properties: + location: + description: >- + The relative location (e.g., path on the file system), which provides the root location to address an attached node. + e.g., a mount point / path such as '/usr/data'. Note: The user must provide it and it cannot be "root". + type: string + constraints: + - min_length: 1 + device: + description: >- + The logical device name which for the attached device (which is represented by the target node in the model). e.g., + '/dev/hda1'. + type: string + required: false + attributes: + device: + description: >- + The logical name of the device as exposed to the instance. + Note: A runtime property that gets set when the model gets instantiated by the orchestrator. + type: string + + tosca.relationships.RoutesTo: + _extensions: + shorthand_name: RoutesTo + type_qualified_name: tosca:RoutesTo + specification: tosca-simple-1.0 + specification_section: 5.6.6 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc397688815' + description: >- + This type represents an intentional network routing between two Endpoints in different networks. + derived_from: tosca.relationships.ConnectsTo + valid_target_types: [ tosca.capabilities.Endpoint ] + + # + # Network + # + + tosca.relationships.network.LinksTo: + _extensions: + shorthand_name: LinksTo + type_qualified_name: tosca:LinksTo + specification: tosca-simple-1.0 + specification_section: 7.5.4 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_RELATIONSHIPS_NETWORK_LINKSTO' + description: >- + This relationship type represents an association relationship between Port and Network node types. + derived_from: tosca.relationships.DependsOn + valid_target_types: [ tosca.capabilities.network.Linkable ] + + tosca.relationships.network.BindsTo: + _extensions: + shorthand_name: BindsTo # ARIA NOTE: the spec says "network.BindsTo" which seems wrong + type_qualified_name: tosca:BindsTo + specification: tosca-simple-1.0 + specification_section: 7.5.5 + specification_url: 'http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html#DEFN_TYPE_RELATIONSHIPS_NETWORK_BINDTO' + description: >- + This type represents a network association relationship between Port and Compute node types. + derived_from: tosca.relationships.DependsOn + valid_target_types: [ tosca.capabilities.network.Bindable ] diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/tosca-simple-1.0.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/tosca-simple-1.0.yaml new file mode 100644 index 0000000..f8cc520 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-1.0/tosca-simple-1.0.yaml @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +imports: + - artifacts.yaml + - capabilities.yaml + - data.yaml + - groups.yaml + - interfaces.yaml + - nodes.yaml + - policies.yaml + - relationships.yaml diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/artifacts.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/artifacts.yaml new file mode 100644 index 0000000..2427d9f --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/artifacts.yaml @@ -0,0 +1,84 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +artifact_types: + + tosca.artifacts.nfv.SwImage: + _extensions: + shorthand_name: SwImage + type_qualified_name: tosca:SwImage + specification: tosca-simple-nfv-1.0 + specification_section: 5.4.1 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896067' + derived_from: tosca.artifacts.Deployment.Image + properties: + name: + description: >- + Name of this software image. + type: string + required: true + version: + description: >- + Version of this software image. + type: string + required: true + checksum: + description: >- + Checksum of the software image file. + type: string + container_format: + description: >- + The container format describes the container file format in which software image is + provided. + type: string + required: true + disk_format: + description: >- + The disk format of a software image is the format of the underlying disk image. + type: string + required: true + min_disk: + description: >- + The minimal disk size requirement for this software image. + type: scalar-unit.size + required: true + min_ram: + description: >- + The minimal disk size requirement for this software image. + type: scalar-unit.size + required: false + size: # ARIA NOTE: section [5.4.1.1 Properties] calls this field 'Size' + description: >- + The size of this software image + type: scalar-unit.size + required: true + sw_image: + description: >- + A reference to the actual software image within VNF Package, or url. + type: string + required: true + operating_system: + description: >- + Identifies the operating system used in the software image. + type: string + required: false + supported _virtualization_enviroment: + description: >- + Identifies the virtualization environments (e.g. hypervisor) compatible with this software + image. + type: list + entry_schema: + type: string + required: false diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/capabilities.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/capabilities.yaml new file mode 100644 index 0000000..7b6363f --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/capabilities.yaml @@ -0,0 +1,70 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +capability_types: + + tosca.capabilities.nfv.VirtualBindable: + _extensions: + shorthand_name: VirtualBindable + type_qualified_name: tosca:VirtualBindable + specification: tosca-simple-nfv-1.0 + specification_section: 5.5.1 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896069' + description: >- + A node type that includes the VirtualBindable capability indicates that it can be pointed by + tosca.relationships.nfv.VirtualBindsTo relationship type. + derived_from: tosca.capabilities.Node + + tosca.capabilities.nfv.Metric: + _extensions: + shorthand_name: Metric + type_qualified_name: tosca:Metric + specification: tosca-simple-nfv-1.0 + specification_section: 5.5.2 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896070' + description: >- + A node type that includes the Metric capability indicates that it can be monitored using an nfv.relationships.Monitor + relationship type. + derived_from: tosca.capabilities.Endpoint + + tosca.capabilities.nfv.VirtualCompute: + _extensions: + shorthand_name: VirtualCompute + type_qualified_name: tosca:VirtualCompute + specification: tosca-simple-nfv-1.0 + specification_section: 5.5.3 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896071' + derived_from: tosca.capabilities.Root + properties: + requested_additional_capabilities: + # ARIA NOTE: in section [5.5.3.1 Properties] the name of this property is + # "request_additional_capabilities", and its type is not a map, but + # tosca.datatypes.nfv.RequestedAdditionalCapability + description: >- + Describes additional capability for a particular VDU. + type: map + entry_schema: + type: tosca.datatypes.nfv.RequestedAdditionalCapability + required: false + virtual_memory: + description: >- + Describes virtual memory of the virtualized compute. + type: tosca.datatypes.nfv.VirtualMemory + required: true + virtual_cpu: + description: >- + Describes virtual CPU(s) of the virtualized compute. + type: tosca.datatypes.nfv.VirtualCpu + required: true diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/data.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/data.yaml new file mode 100644 index 0000000..889dcf7 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/data.yaml @@ -0,0 +1,318 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +data_types: + + tosca.datatypes.nfv.L2AddressData: + # TBD + _extensions: + shorthand_name: L2AddressData + type_qualified_name: tosca:L2AddressData + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.1 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896055' + + tosca.datatypes.nfv.L3AddressData: + _extensions: + shorthand_name: L3AddressData + type_qualified_name: tosca:L3AddressData + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.2 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896056' + description: >- + The L3AddressData type is a complex TOSCA data type used to describe L3AddressData information + element as defined in [ETSI GS NFV-IFA 011], it provides the information on the IP addresses + to be assigned to the connection point instantiated from the parent Connection Point + Descriptor. + derived_from: tosca.datatypes.Root + properties: + ip_address_assignment: + description: >- + Specify if the address assignment is the responsibility of management and orchestration + function or not. If it is set to True, it is the management and orchestration function + responsibility. + type: boolean + required: true + floating_ip_activated: + description: Specify if the floating IP scheme is activated on the Connection Point or not. + type: boolean + required: true + ip_address_type: + description: >- + Define address type. The address type should be aligned with the address type supported by + the layer_protocol properties of the parent VnfExtCpd. + type: string + required: false + constraints: + - valid_values: [ ipv4, ipv6 ] + number_of_ip_address: + description: >- + Minimum number of IP addresses to be assigned. + type: integer + required: false + + tosca.datatypes.nfv.AddressData: + _extensions: + shorthand_name: AddressData + type_qualified_name: tosca:AddressData + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.3 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896057' + description: >- + The AddressData type is a complex TOSCA data type used to describe AddressData information + element as defined in [ETSI GS NFV-IFA 011], it provides information on the addresses to be + assigned to the connection point(s) instantiated from a Connection Point Descriptor. + derived_from: tosca.datatypes.Root + properties: + address_type: + description: >- + Describes the type of the address to be assigned to the connection point instantiated from + the parent Connection Point Descriptor. The content type shall be aligned with the address + type supported by the layerProtocol property of the parent Connection Point Descriptor. + type: string + required: true + constraints: + - valid_values: [ mac_address, ip_address ] + l2_address_data: + # Shall be present when the addressType is mac_address. + description: >- + Provides the information on the MAC addresses to be assigned to the connection point(s) + instantiated from the parent Connection Point Descriptor. + type: tosca.datatypes.nfv.L2AddressData # Empty in "GS NFV IFA011 V0.7.3" + required: false + l3_address_data: + # Shall be present when the addressType is ip_address. + description: >- + Provides the information on the IP addresses to be assigned to the connection point + instantiated from the parent Connection Point Descriptor. + type: tosca.datatypes.nfv.L3AddressData + required: false + + tosca.datatypes.nfv.VirtualNetworkInterfaceRequirements: + _extensions: + shorthand_name: VirtualNetworkInterfaceRequirements + type_qualified_name: tosca:VirtualNetworkInterfaceRequirements + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.4 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896058' + description: >- + The VirtualNetworkInterfaceRequirements type is a complex TOSCA data type used to describe + VirtualNetworkInterfaceRequirements information element as defined in [ETSI GS NFV-IFA 011], + it provides the information to specify requirements on a virtual network interface realising the + CPs instantiated from this CPD. + derived_from: tosca.datatypes.Root + properties: + name: + description: >- + Provides a human readable name for the requirement. + type: string + required: false + description: + description: >- + Provides a human readable description for the requirement. + type: string + required: false + support_mandatory: + description: >- + Indicates whether fulfilling the constraint is mandatory (TRUE) for successful operation + or desirable (FALSE). + type: boolean + required: false + requirement: + description: >- + Specifies a requirement such as the support of SR-IOV, a particular data plane + acceleration library, an API to be exposed by a NIC, etc. + type: string # ARIA NOTE: the spec says "not specified", but TOSCA requires a type + required: true + + tosca.datatypes.nfv.ConnectivityType: + _extensions: + shorthand_name: ConnectivityType + type_qualified_name: tosca:ConnectivityType + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.5 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896059' + description: >- + The TOSCA ConnectivityType type is a complex TOSCA data type used to describe ConnectivityType + information element as defined in [ETSI GS NFV-IFA 011]. + derived_from: tosca.datatypes.Root + properties: + layer_protocol: + description: >- + Identifies the protocol this VL gives access to (ethernet, mpls, odu2, ipv4, ipv6, + pseudo_wire). + type: string + required: true + constraints: + - valid_values: [ ethernet, mpls, odu2, ipv4, ipv6, pseudo_wire ] + flow_pattern: + description: >- + Identifies the flow pattern of the connectivity (Line, Tree, Mesh). + type: string + required: false + + tosca.datatypes.nfv.RequestedAdditionalCapability: + _extensions: + shorthand_name: RequestedAdditionalCapability + type_qualified_name: tosca:RequestedAdditionalCapability + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.6 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896060' + description: >- + RequestAdditionalCapability describes additional capability for a particular VDU. + derived_from: tosca.datatypes.Root + properties: + request_additional_capability_name: + description: >- + Identifies a requested additional capability for the VDU. + type: string + required: true + support_mandatory: + description: >- + Indicates whether the requested additional capability is mandatory for successful + operation. + type: string + required: true + min_requested_additional_capability_version: + description: >- + Identifies the minimum version of the requested additional capability. + type: string + required: false + preferred_requested_additional_capability_version: + description: >- + Identifies the preferred version of the requested additional capability. + type: string + required: false + target_performance_parameters: + description: >- + Identifies specific attributes, dependent on the requested additional capability type. + type: map + entry_schema: + type: string + required: true + + tosca.datatypes.nfv.VirtualMemory: + _extensions: + shorthand_name: VirtualMemory + type_qualified_name: tosca:VirtualMemory + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.7 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896061' + description: >- + VirtualMemory describes virtual memory for a particular VDU. + derived_from: tosca.datatypes.Root + properties: + virtual_mem_size: + description: Amount of virtual memory. + type: scalar-unit.size + required: true + virtual_mem_oversubscription_policy: + description: >- + The memory core oversubscription policy in terms of virtual memory to physical memory on + the platform. The cardinality can be 0 during the allocation request, if no particular + value is requested. + type: string + required: false + numa_enabled: + description: >- + It specifies the memory allocation to be cognisant of the relevant process/core + allocation. The cardinality can be 0 during the allocation request, if no particular value + is requested. + type: boolean + required: false + + tosca.datatypes.nfv.VirtualCpu: + _extensions: + shorthand_name: VirtualCpu + type_qualified_name: tosca:VirtualCpu + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.8 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896062' + description: >- + VirtualMemory describes virtual memory for a particular VDU. + derived_from: tosca.datatypes.Root + properties: + cpu_architecture: + description: >- + CPU architecture type. Examples are x86, ARM. + type: string + required: false + num_virtual_cpu: + description: >- + Number of virtual CPUs. + type: integer + required: true + virtual_cpu_clock: + description: >- + Minimum virtual CPU clock rate. + type: scalar-unit.frequency + required: false + virtual_cpu_oversubscription_policy: + description: >- + CPU core oversubscription policy. + type: string + required: false + virtual_cpu_pinning: + description: >- + The virtual CPU pinning configuration for the virtualized compute resource. + type: tosca.datatypes.nfv.VirtualCpuPinning + required: false + + tosca.datatypes.nfv.VirtualCpuPinning: + _extensions: + shorthand_name: VirtualCpuPinning + type_qualified_name: tosca:VirtualCpuPinning + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.9 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896064' + description: >- + VirtualCpuPinning describes CPU pinning configuration for a particular CPU. + derived_from: tosca.datatypes.Root + properties: + cpu_pinning_policy: + description: >- + Indicates the policy for CPU pinning. + type: string + constraints: + - valid_values: [ static, dynamic ] + required: false + cpu_pinning_map: + description: >- + If cpuPinningPolicy is defined as "static", the cpuPinningMap provides the map of pinning + virtual CPU cores to physical CPU cores/threads. + type: map + entry_schema: + type: string + required: false + + tosca.datatypes.nfv.VnfcConfigurableProperties: + _extensions: + shorthand_name: VnfcconfigurableProperties + type_qualified_name: tosca:VnfcconfigurableProperties + specification: tosca-simple-nfv-1.0 + specification_section: 5.3.10 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896065' + # ARIA NOTE: description is mangled in spec + description: >- + VnfcConfigurableProperties describes additional configurable properties of a VNFC. + derived_from: tosca.datatypes.Root + properties: + additional_vnfc_configurable_properties: + description: >- + Describes additional configuration for VNFC. + type: map + entry_schema: + type: string + required: false diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/nodes.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/nodes.yaml new file mode 100644 index 0000000..8d1f0a2 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/nodes.yaml @@ -0,0 +1,260 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +node_types: + + tosca.nodes.nfv.VDU.Compute: + _extensions: + shorthand_name: VDU.Compute + type_qualified_name: tosca:VDU.Compute + specification: tosca-simple-nfv-1.0 + specification_section: 5.9.2 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896079' + description: >- + The TOSCA nfv.VDU.Compute node type represents the virtual compute part of a VDU entity which + it mainly describes the deployment and operational behavior of a VNF component (VNFC), as + defined by [ETSI NFV IFA011]. + derived_from: tosca.nodes.Compute + properties: + name: + description: >- + Human readable name of the VDU. + type: string + required: true + description: + description: >- + Human readable description of the VDU. + type: string + required: true + boot_order: + description: >- + The key indicates the boot index (lowest index defines highest boot priority). + The Value references a descriptor from which a valid boot device is created e.g. + VirtualStorageDescriptor from which a VirtualStorage instance is created. If no boot order + is defined the default boot order defined in the VIM or NFVI shall be used. + type: list # ARIA NOTE: an explicit index (boot index) is unnecessary, contrary to IFA011 + entry_schema: + type: string + required: false + nfvi_constraints: + description: >- + Describes constraints on the NFVI for the VNFC instance(s) created from this VDU. + For example, aspects of a secure hosting environment for the VNFC instance that involve + additional entities or processes. More software images can be attached to the + virtualization container using virtual_storage. + type: list + entry_schema: + type: string + required: false + configurable_properties: + description: >- + Describes the configurable properties of all VNFC instances based on this VDU. + type: map + entry_schema: + type: tosca.datatypes.nfv.VnfcConfigurableProperties + required: true + attributes: + # ARIA NOTE: The attributes are only described in section [5.9.2.5 Definition], but are not + # mentioned in section [5.9.2.2 Attributes]. Additionally, it does not seem to make sense to + # deprecate inherited attributes, as it breaks the inheritence contract. + private_address: + type: string + status: deprecated + public_address: + type: string + status: deprecated + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + status: deprecated + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + status: deprecated + capabilities: + virtual_compute: + description: >- + Describes virtual compute resources capabilities. + type: tosca.capabilities.nfv.VirtualCompute + virtual_binding: + description: >- + Defines ability of VirtualBindable. + type: tosca.capabilities.nfv.VirtualBindable + monitoring_parameter: + # ARIA NOTE: commented out in 5.9.2.5 + description: >- + Monitoring parameter, which can be tracked for a VNFC based on this VDU. Examples include: + memory-consumption, CPU-utilisation, bandwidth-consumption, VNFC downtime, etc. + type: tosca.capabilities.nfv.Metric + #requirements: + # ARIA NOTE: virtual_storage is TBD + + # ARIA NOTE: csd04 attempts to deprecate the inherited local_storage requirement, but this + # is not possible in TOSCA + artifacts: + sw_image: + description: >- + Describes the software image which is directly loaded on the virtualization container + realizing this virtual storage. + file: '' # ARIA NOTE: missing value even though it is required in TOSCA + type: tosca.artifacts.nfv.SwImage + + tosca.nodes.nfv.VDU.VirtualStorage: + _extensions: + shorthand_name: VirtualStorage # ARIA NOTE: seems wrong in spec + type_qualified_name: tosca:VirtualStorage # ARIA NOTE: seems wrong in spec + specification: tosca-simple-nfv-1.0 + specification_section: 5.9.3 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896080' + description: >- + The NFV VirtualStorage node type represents a virtual storage entity which it describes the + deployment and operational behavior of a virtual storage resources, as defined by + [ETSI NFV IFA011]. + derived_from: tosca.nodes.Root + properties: + type_of_storage: + description: >- + Type of virtualized storage resource. + type: string + required: true + size_of_storage: + description: >- + Size of virtualized storage resource (in GB). + type: scalar-unit.size + required: true + rdma_enabled: + description: >- + Indicate if the storage support RDMA. + type: boolean + required: false + artifacts: + sw_image: + description: >- + Describes the software image which is directly loaded on the virtualization container + realizing this virtual storage. + file: '' # ARIA NOTE: missing in spec + type: tosca.artifacts.nfv.SwImage + + tosca.nodes.nfv.Cpd: + _extensions: + shorthand_name: Cpd + type_qualified_name: tosca:Cpd + specification: tosca-simple-nfv-1.0 + specification_section: 5.9.4 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896081' + description: >- + The TOSCA nfv.Cpd node represents network connectivity to a compute resource or a VL as defined + by [ETSI GS NFV-IFA 011]. This is an abstract type used as parent for the various Cpd types. + derived_from: tosca.nodes.Root + properties: + layer_protocol: + description: >- + Identifies which protocol the connection point uses for connectivity purposes. + type: string + constraints: + - valid_values: [ ethernet, mpls, odu2, ipv4, ipv6, pseudo_wire ] + required: false + role: # Name in ETSI NFV IFA011 v0.7.3 cpRole + description: >- + Identifies the role of the port in the context of the traffic flow patterns in the VNF or + parent NS. For example a VNF with a tree flow pattern within the VNF will have legal + cpRoles of ROOT and LEAF. + type: string + constraints: + - valid_values: [ root, leaf ] + required: false + description: + description: >- + Provides human-readable information on the purpose of the connection point + (e.g. connection point for control plane traffic). + type: string + required: false + address_data: + description: >- + Provides information on the addresses to be assigned to the connection point(s) instantiated + from this Connection Point Descriptor. + type: list + entry_schema: + type: tosca.datatypes.nfv.AddressData + required: false + + tosca.nodes.nfv.VduCpd: + _extensions: + shorthand_name: VduCpd + type_qualified_name: tosca:VduCpd + specification: tosca-simple-nfv-1.0 + specification_section: 5.9.5 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896082' + description: >- + The TOSCA nfv.VduCpd node type represents a type of TOSCA Cpd node and describes network + connectivity between a VNFC instance (based on this VDU) and an internal VL as defined by + [ETSI GS NFV-IFA 011]. + derived_from: tosca.nodes.nfv.Cpd + properties: + bitrate_requirement: + description: >- + Bitrate requirement on this connection point. + type: integer + required: false + virtual_network_interface_requirements: + description: >- + Specifies requirements on a virtual network interface realising the CPs instantiated from + this CPD. + type: list + entry_schema: + type: VirtualNetworkInterfaceRequirements + required: false + requirements: + # ARIA NOTE: seems to be a leftover from csd03 + # - virtual_link: + # description: Describes the requirements for linking to virtual link + # capability: tosca.capabilities.nfv.VirtualLinkable + # relationship: tosca.relationships.nfv.VirtualLinksTo + # node: tosca.nodes.nfv.VnfVirtualLinkDesc + - virtual_binding: + capability: tosca.capabilities.nfv.VirtualBindable + relationship: tosca.relationships.nfv.VirtualBindsTo + node: tosca.nodes.nfv.VDU.Compute # ARIA NOTE: seems wrong in spec + + tosca.nodes.nfv.VnfVirtualLinkDesc: + _extensions: + shorthand_name: VnfVirtualLinkDesc + type_qualified_name: tosca:VnfVirtualLinkDesc + specification: tosca-simple-nfv-1.0 + specification_section: 5.9.6 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896083' + description: >- + The TOSCA nfv.VnfVirtualLinkDesc node type represents a logical internal virtual link as + defined by [ETSI GS NFV-IFA 011]. + derived_from: tosca.nodes.Root + properties: + connectivity_type: + description: >- + specifies the protocol exposed by the VL and the flow pattern supported by the VL. + type: tosca.datatypes.nfv.ConnectivityType + required: true + description: + description: >- + Provides human-readable information on the purpose of the VL (e.g. control plane traffic). + type: string + required: false + test_access: + description: >- + Test access facilities available on the VL (e.g. none, passive, monitoring, or active + (intrusive) loopbacks at endpoints. + type: string + required: false diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/relationships.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/relationships.yaml new file mode 100644 index 0000000..4cf99a2 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/relationships.yaml @@ -0,0 +1,43 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +relationship_types: + + tosca.relationships.nfv.VirtualBindsTo: + _extensions: + shorthand_name: VirtualBindsTo + type_qualified_name: tosca:VirtualBindsTo + specification: tosca-simple-nfv-1.0 + specification_section: 5.7.1 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896074' + description: >- + This relationship type represents an association relationship between VDU and CP node types. + derived_from: tosca.relationships.DependsOn + valid_target_types: [ tosca.capabilities.nfv.VirtualBindable ] + + # ARIA NOTE: csd04 lacks the definition of tosca.relationships.nfv.Monitor (the derived_from and + # valid_target_types), so we are using the definition in csd03 section 8.4.2. + tosca.relationships.nfv.Monitor: + _extensions: + shorthand_name: Monitor + type_qualified_name: tosca:Monitor + specification: tosca-simple-nfv-1.0 + specification_section: 5.7.2 + specification_url: 'http://docs.oasis-open.org/tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html#_Toc482896075' + description: >- + This relationship type represents an association relationship to the Metric capability of VDU + node types. + derived_from: tosca.relationships.ConnectsTo + valid_target_types: [ tosca.capabilities.nfv.Metric ] diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/tosca-simple-nfv-1.0.yaml b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/tosca-simple-nfv-1.0.yaml new file mode 100644 index 0000000..764c739 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/profiles/tosca-simple-nfv-1.0/tosca-simple-nfv-1.0.yaml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +imports: + - artifacts.yaml + - capabilities.yaml + - data.yaml + - nodes.yaml + - relationships.yaml diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_nfv_v1_0/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_nfv_v1_0/__init__.py new file mode 100644 index 0000000..313e3ef --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_nfv_v1_0/__init__.py @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from .presenter import ToscaSimpleNfvPresenter1_0 + +__all__ = ( + 'ToscaSimpleNfvPresenter1_0',) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_nfv_v1_0/presenter.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_nfv_v1_0/presenter.py new file mode 100644 index 0000000..64178aa --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_nfv_v1_0/presenter.py @@ -0,0 +1,43 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import FrozenList +from aria.utils.caching import cachedmethod + +from ..simple_v1_0 import ToscaSimplePresenter1_0 + + +class ToscaSimpleNfvPresenter1_0(ToscaSimplePresenter1_0): # pylint: disable=invalid-name,abstract-method + """ + ARIA presenter for the `TOSCA Simple Profile for NFV v1.0 csd04 <http://docs.oasis-open.org + /tosca/tosca-nfv/v1.0/csd04/tosca-nfv-v1.0-csd04.html>`__. + + Supported ``tosca_definitions_version`` values: + + * ``tosca_simple_profile_for_nfv_1_0`` + """ + + DSL_VERSIONS = ('tosca_simple_profile_for_nfv_1_0',) + ALLOWED_IMPORTED_DSL_VERSIONS = ('tosca_simple_yaml_1_0', 'tosca_simple_profile_for_nfv_1_0') + SIMPLE_PROFILE_FOR_NFV_LOCATION = 'tosca-simple-nfv-1.0/tosca-simple-nfv-1.0.yaml' + + # Presenter + + @cachedmethod + def _get_import_locations(self, context): + import_locations = super(ToscaSimpleNfvPresenter1_0, self)._get_import_locations(context) + if context.presentation.import_profile: + return FrozenList([self.SIMPLE_PROFILE_FOR_NFV_LOCATION] + import_locations) + return import_locations diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/__init__.py new file mode 100644 index 0000000..61995db --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/__init__.py @@ -0,0 +1,199 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Parser implementation of `TOSCA Simple Profile v1.0 cos01 <http://docs.oasis-open.org/tosca +/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html>`__. + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.ToscaSimplePresenter1_0 + +Assignments +----------- + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.PropertyAssignment + aria_extension_tosca.simple_v1_0.OperationAssignment + aria_extension_tosca.simple_v1_0.InterfaceAssignment + aria_extension_tosca.simple_v1_0.RelationshipAssignment + aria_extension_tosca.simple_v1_0.RequirementAssignment + aria_extension_tosca.simple_v1_0.AttributeAssignment + aria_extension_tosca.simple_v1_0.CapabilityAssignment + aria_extension_tosca.simple_v1_0.ArtifactAssignment + +Definitions +----------- + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.PropertyDefinition + aria_extension_tosca.simple_v1_0.AttributeDefinition + aria_extension_tosca.simple_v1_0.ParameterDefinition + aria_extension_tosca.simple_v1_0.OperationDefinition + aria_extension_tosca.simple_v1_0.InterfaceDefinition + aria_extension_tosca.simple_v1_0.RelationshipDefinition + aria_extension_tosca.simple_v1_0.RequirementDefinition + aria_extension_tosca.simple_v1_0.CapabilityDefinition + +Filters +------- + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.CapabilityFilter + aria_extension_tosca.simple_v1_0.NodeFilter + +Miscellaneous +------------- + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.Description + aria_extension_tosca.simple_v1_0.MetaData + aria_extension_tosca.simple_v1_0.Repository + aria_extension_tosca.simple_v1_0.Import + aria_extension_tosca.simple_v1_0.ConstraintClause + aria_extension_tosca.simple_v1_0.EntrySchema + aria_extension_tosca.simple_v1_0.OperationImplementation + aria_extension_tosca.simple_v1_0.SubstitutionMappingsRequirement + aria_extension_tosca.simple_v1_0.SubstitutionMappingsCapability + aria_extension_tosca.simple_v1_0.SubstitutionMappings + +Templates +--------- + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.NodeTemplate + aria_extension_tosca.simple_v1_0.RelationshipTemplate + aria_extension_tosca.simple_v1_0.GroupTemplate + aria_extension_tosca.simple_v1_0.PolicyTemplate + aria_extension_tosca.simple_v1_0.TopologyTemplate + aria_extension_tosca.simple_v1_0.ServiceTemplate + +Types +----- + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.ArtifactType + aria_extension_tosca.simple_v1_0.DataType + aria_extension_tosca.simple_v1_0.CapabilityType + aria_extension_tosca.simple_v1_0.InterfaceType + aria_extension_tosca.simple_v1_0.RelationshipType + aria_extension_tosca.simple_v1_0.NodeType + aria_extension_tosca.simple_v1_0.GroupType + aria_extension_tosca.simple_v1_0.PolicyType + +Data types +---------- + +.. autosummary:: + :nosignatures: + + aria_extension_tosca.simple_v1_0.Timestamp + aria_extension_tosca.simple_v1_0.Version + aria_extension_tosca.simple_v1_0.Range + aria_extension_tosca.simple_v1_0.List + aria_extension_tosca.simple_v1_0.Map + aria_extension_tosca.simple_v1_0.ScalarSize + aria_extension_tosca.simple_v1_0.ScalarTime + aria_extension_tosca.simple_v1_0.ScalarFrequency +""" + +from .presenter import ToscaSimplePresenter1_0 +from .assignments import (PropertyAssignment, OperationAssignment, InterfaceAssignment, + RelationshipAssignment, RequirementAssignment, AttributeAssignment, + CapabilityAssignment, ArtifactAssignment) +from .definitions import (PropertyDefinition, AttributeDefinition, ParameterDefinition, + OperationDefinition, InterfaceDefinition, RelationshipDefinition, + RequirementDefinition, CapabilityDefinition) +from .filters import CapabilityFilter, NodeFilter +from .misc import (Description, MetaData, Repository, Import, ConstraintClause, EntrySchema, + OperationImplementation, SubstitutionMappingsRequirement, + SubstitutionMappingsCapability, SubstitutionMappings) +from .templates import (NodeTemplate, RelationshipTemplate, GroupTemplate, PolicyTemplate, + TopologyTemplate, ServiceTemplate) +from .types import (ArtifactType, DataType, CapabilityType, InterfaceType, RelationshipType, + NodeType, GroupType, PolicyType) +from .data_types import (Timestamp, Version, Range, List, Map, ScalarSize, ScalarTime, + ScalarFrequency) + +MODULES = ( + 'modeling', + 'presentation') + +__all__ = ( + 'MODULES', + 'ToscaSimplePresenter1_0', + 'PropertyAssignment', + 'OperationAssignment', + 'InterfaceAssignment', + 'RelationshipAssignment', + 'RequirementAssignment', + 'AttributeAssignment', + 'CapabilityAssignment', + 'ArtifactAssignment', + 'PropertyDefinition', + 'AttributeDefinition', + 'ParameterDefinition', + 'OperationDefinition', + 'InterfaceDefinition', + 'RelationshipDefinition', + 'RequirementDefinition', + 'CapabilityDefinition', + 'CapabilityFilter', + 'NodeFilter', + 'Description', + 'MetaData', + 'Repository', + 'Import', + 'ConstraintClause', + 'EntrySchema', + 'OperationImplementation', + 'SubstitutionMappingsRequirement', + 'SubstitutionMappingsCapability', + 'SubstitutionMappings', + 'NodeTemplate', + 'RelationshipTemplate', + 'GroupTemplate', + 'PolicyTemplate', + 'TopologyTemplate', + 'ServiceTemplate', + 'ArtifactType', + 'DataType', + 'CapabilityType', + 'InterfaceType', + 'RelationshipType', + 'NodeType', + 'GroupType', + 'PolicyType', + 'Timestamp', + 'Version', + 'Range', + 'List', + 'Map', + 'ScalarSize', + 'ScalarTime', + 'ScalarFrequency') diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/assignments.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/assignments.py new file mode 100644 index 0000000..7b48ed0 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/assignments.py @@ -0,0 +1,453 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import FrozenDict +from aria.utils.caching import cachedmethod +from aria.parser import implements_specification +from aria.parser.presentation import (AsIsPresentation, has_fields, allow_unknown_fields, + short_form_field, primitive_field, object_field, + object_dict_field, object_dict_unknown_fields, + field_validator, type_validator) + +from .filters import NodeFilter +from .misc import Description, OperationImplementation +from .modeling.parameters import get_assigned_and_defined_parameter_values +from .presentation.extensible import ExtensiblePresentation +from .presentation.field_validators import (node_template_or_type_validator, + relationship_template_or_type_validator, + capability_definition_or_type_validator, + node_filter_validator) +from .presentation.types import (convert_name_to_full_type_name, get_type_by_name) + + + +@implements_specification('3.5.9', 'tosca-simple-1.0') +class PropertyAssignment(AsIsPresentation): + """ + This section defines the grammar for assigning values to named properties within TOSCA Node and + Relationship templates that are defined in their corresponding named types. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_PROPERTY_VALUE_ASSIGNMENT>`__ + """ + + +@short_form_field('implementation') +@has_fields +@implements_specification('3.5.13-2', 'tosca-simple-1.0') +class OperationAssignment(ExtensiblePresentation): + """ + An operation definition defines a named function or procedure that can be bound to an + implementation artifact (e.g., a script). + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_OPERATION_DEF>`__ + """ + + @object_field(Description) + def description(self): + """ + The optional description string for the associated named operation. + + :type: :class:`Description` + """ + + @object_field(OperationImplementation) + def implementation(self): + """ + The optional implementation artifact name (e.g., a script file name within a TOSCA CSAR + file). + + :type: :class:`OperationImplementation` + """ + + @object_dict_field(PropertyAssignment) + def inputs(self): + """ + The optional list of input property assignments (i.e., parameters assignments) for operation + definitions that are within TOSCA Node or Relationship Template definitions. This includes + when operation definitions are included as part of a Requirement assignment in a Node + Template. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @cachedmethod + def _get_extensions(self, context): + def update_inherited_extensions(extensions, interface_type): + parent = interface_type._get_parent(context) + if parent is not None: + update_inherited_extensions(extensions, parent) + operation_definition = interface_type.operations.get(self._name) + if operation_definition is not None: + if operation_definition._extensions: + extensions.update(operation_definition._extensions) + + extensions = {} + update_inherited_extensions(extensions, self._container._get_type(context)) + if self._container._extensions: + extensions.update(self._container._extensions) + if self._extensions: + extensions.update(self._extensions) + return extensions + + +@allow_unknown_fields +@has_fields +@implements_specification('3.5.14-2', 'tosca-simple-1.0') +class InterfaceAssignment(ExtensiblePresentation): + """ + An interface definition defines a named interface that can be associated with a Node or + Relationship Type. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_INTERFACE_DEF>`__ + """ + + @object_dict_field(PropertyAssignment) + def inputs(self): + """ + The optional list of input property assignments (i.e., parameters assignments) for interface + definitions that are within TOSCA Node or Relationship Template definitions. This includes + when interface definitions are referenced as part of a Requirement assignment in a Node + Template. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @object_dict_unknown_fields(OperationAssignment) + def operations(self): + """ + :type: {:obj:`basestring`: :class:`OperationAssignment`} + """ + + @cachedmethod + def _get_type(self, context): + the_type = self._container._get_type(context) + + if isinstance(the_type, tuple): + # In RelationshipAssignment + the_type = the_type[0] # This could be a RelationshipTemplate + + interface_definitions = the_type._get_interfaces(context) \ + if the_type is not None else None + interface_definition = interface_definitions.get(self._name) \ + if interface_definitions is not None else None + return interface_definition._get_type(context) \ + if interface_definition is not None else None + + def _validate(self, context): + super(InterfaceAssignment, self)._validate(context) + if self.operations: + for operation in self.operations.itervalues(): # pylint: disable=no-member + operation._validate(context) + + +@short_form_field('type') +@has_fields +class RelationshipAssignment(ExtensiblePresentation): + """ + Relationship assignment. + """ + + @field_validator(relationship_template_or_type_validator) + @primitive_field(str) + def type(self): + """ + The optional reserved keyname used to provide the name of the Relationship Type for the + requirement assignment's relationship keyname. + + :type: :obj:`basestring` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + ARIA NOTE: This field is not mentioned in the spec, but is implied. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @object_dict_field(InterfaceAssignment) + def interfaces(self): + """ + The optional reserved keyname used to reference declared (named) interface definitions of + the corresponding Relationship Type in order to provide Property assignments for these + interfaces or operations of these interfaces. + + :type: {:obj:`basestring`: :class:`InterfaceAssignment`} + """ + + @cachedmethod + def _get_type(self, context): + type_name = self.type + if type_name is not None: + the_type = context.presentation.get_from_dict('service_template', 'topology_template', + 'relationship_templates', type_name) + if the_type is not None: + return the_type, 'relationship_template' + the_type = get_type_by_name(context, type_name, 'relationship_types') + if the_type is not None: + return the_type, 'relationship_type' + return None, None + + +@short_form_field('node') +@has_fields +@implements_specification('3.7.2', 'tosca-simple-1.0') +class RequirementAssignment(ExtensiblePresentation): + """ + A Requirement assignment allows template authors to provide either concrete names of TOSCA + templates or provide abstract selection criteria for providers to use to find matching TOSCA + templates that are used to fulfill a named requirement's declared TOSCA Node Type. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_REQUIREMENT_ASSIGNMENT>`__ + """ + + # The example in 3.7.2.2.2 shows unknown fields in addition to these, but is this a mistake? + + @field_validator(capability_definition_or_type_validator) + @primitive_field(str) + def capability(self): + """ + The optional reserved keyname used to provide the name of either a: + + * Capability definition within a target node template that can fulfill the requirement. + * Capability Type that the provider will use to select a type-compatible target node + template to fulfill the requirement at runtime. + + :type: :obj:`basestring` + """ + + @field_validator(node_template_or_type_validator) + @primitive_field(str) + def node(self): + """ + The optional reserved keyname used to identify the target node of a relationship. + Specifically, it is used to provide either a: + + * Node Template name that can fulfill the target node requirement. + * Node Type name that the provider will use to select a type-compatible node template to + fulfill the requirement at runtime. + + :type: :obj:`basestring` + """ + + @object_field(RelationshipAssignment) + def relationship(self): + """ + The optional reserved keyname used to provide the name of either a: + + * Relationship Template to use to relate the source node to the (capability in the) target + node when fulfilling the requirement. + * Relationship Type that the provider will use to select a type-compatible relationship + template to relate the source node to the target node at runtime. + + :type: :class:`RelationshipAssignment` + """ + + @field_validator(node_filter_validator) + @object_field(NodeFilter) + def node_filter(self): + """ + The optional filter definition that TOSCA orchestrators or providers would use to select a + type-compatible target node that can fulfill the associated abstract requirement at runtime. + + :type: :class:`NodeFilter` + """ + + @cachedmethod + def _get_node(self, context): + node = self.node + + if node is not None: + node_template = context.presentation.get_from_dict('service_template', + 'topology_template', + 'node_templates', node) + if node_template is not None: + return node_template, 'node_template' + node_type = get_type_by_name(context, node, 'node_types') + if node_type is not None: + return node_type, 'node_type' + + return None, None + + @cachedmethod + def _get_capability(self, context): + capability = self.capability + + if capability is not None: + node, node_variant = self._get_node(context) + if node_variant == 'node_template': + capabilities = node._get_capabilities(context) + if capability in capabilities: + return capabilities[capability], 'capability_assignment' + capability_type = get_type_by_name(context, capability, 'capability_types') + if capability_type is not None: + return capability_type, 'capability_type' + + return None, None + + +@implements_specification('3.5.11', 'tosca-simple-1.0') +class AttributeAssignment(AsIsPresentation): + """ + This section defines the grammar for assigning values to named attributes within TOSCA Node and + Relationship templates which are defined in their corresponding named types. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_ATTRIBUTE_VALUE_ASSIGNMENT>`__ + """ + + +@has_fields +@implements_specification('3.7.1', 'tosca-simple-1.0') +class CapabilityAssignment(ExtensiblePresentation): + """ + A capability assignment allows node template authors to assign values to properties and + attributes for a named capability definition that is part of a Node Template's type definition. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_CAPABILITY_ASSIGNMENT>`__ + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property definitions for the Capability definition. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @object_dict_field(AttributeAssignment) + def attributes(self): + """ + An optional list of attribute definitions for the Capability definition. + + :type: {:obj:`basestring`: :class:`AttributeAssignment`} + """ + + @cachedmethod + def _get_definition(self, context): + node_type = self._container._get_type(context) + capability_definitions = node_type._get_capabilities(context) \ + if node_type is not None else None + return capability_definitions.get(self._name) \ + if capability_definitions is not None else None + + @cachedmethod + def _get_type(self, context): + capability_definition = self._get_definition(context) + return capability_definition._get_type(context) \ + if capability_definition is not None else None + + +@has_fields +@implements_specification('3.5.6', 'tosca-simple-1.0') +class ArtifactAssignmentForType(ExtensiblePresentation): + """ + An artifact definition defines a named, typed file that can be associated with Node Type or Node + Template and used by orchestration engine to facilitate deployment and implementation of + interface operations. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_ARTIFACT_DEF>`__ + """ + + @field_validator(type_validator('artifact type', convert_name_to_full_type_name, + 'artifact_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required artifact type for the artifact definition. + + :type: :obj:`basestring` + """ + + @primitive_field(str, required=True) + def file(self): + """ + The required URI string (relative or absolute) which can be used to locate the artifact's + file. + + :type: :obj:`basestring` + """ + + @field_validator(type_validator('repository', 'repositories')) + @primitive_field(str) + def repository(self): + """ + The optional name of the repository definition which contains the location of the external + repository that contains the artifact. The artifact is expected to be referenceable by its + file URI within the repository. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the artifact definition. + + :type: :class:`Description` + """ + + @primitive_field(str) + def deploy_path(self): + """ + The file path the associated file would be deployed into within the target node's container. + + :type: :obj:`basestring` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + ARIA NOTE: This field is not mentioned in the spec, but is implied. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'artifact_types') + + @cachedmethod + def _get_repository(self, context): + return context.presentation.get_from_dict('service_template', 'repositories', + self.repository) + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_parameter_values(context, self, 'property')) + + @cachedmethod + def _validate(self, context): + super(ArtifactAssignmentForType, self)._validate(context) + + +class ArtifactAssignment(ArtifactAssignmentForType): + @cachedmethod + def _validate(self, context): + super(ArtifactAssignment, self)._validate(context) + self._get_property_values(context) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/data_types.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/data_types.py new file mode 100644 index 0000000..216f1e4 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/data_types.py @@ -0,0 +1,561 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re +from datetime import (datetime, tzinfo, timedelta) +try: + from functools import total_ordering +except ImportError: + from total_ordering import total_ordering + +from aria.parser import implements_specification +from aria.utils.collections import (StrictDict, OrderedDict) +from aria.utils.formatting import safe_repr + +from .modeling.data_types import (coerce_to_data_type_class, report_issue_for_bad_format, + coerce_value) + + +class Timezone(tzinfo): + """ + Timezone as fixed offset in hours and minutes east of UTC. + """ + + def __init__(self, hours=0, minutes=0): + super(Timezone, self).__init__() + self._offset = timedelta(hours=hours, minutes=minutes) + + def utcoffset(self, dt): # pylint: disable=unused-argument + return self._offset + + def tzname(self, dt): # pylint: disable=unused-argument + return str(self._offset) + + def dst(self, dt): # pylint: disable=unused-argument + return Timezone._ZERO + + _ZERO = timedelta(0) + + +UTC = Timezone() + + +@total_ordering +@implements_specification('timestamp', 'yaml-1.1') +class Timestamp(object): + ''' + TOSCA timestamps follow the YAML specification, which in turn is a variant of ISO8601. + + Long forms and short forms (without time of day and assuming UTC timezone) are supported for + parsing. The canonical form (for rendering) matches the long form at the UTC timezone. + + See the `Timestamp Language-Independent Type for YAML Version 1.1 (Working Draft 2005-01-18) + <http://yaml.org/type/timestamp.html>`__ + ''' + + REGULAR_SHORT = r'^(?P<year>[0-9][0-9][0-9][0-9])-(?P<month>[0-9][0-9])-(?P<day>[0-9][0-9])$' + REGULAR_LONG = \ + r'^(?P<year>[0-9][0-9][0-9][0-9])-(?P<month>[0-9][0-9]?)-(?P<day>[0-9][0-9]?)' + \ + r'([Tt]|[ \t]+)' \ + r'(?P<hour>[0-9][0-9]?):(?P<minute>[0-9][0-9]):(?P<second>[0-9][0-9])' + \ + r'(?P<fraction>\.[0-9]*)?' + \ + r'(([ \t]*)Z|(?P<tzhour>[-+][0-9][0-9])?(:(?P<tzminute>[0-9][0-9])?)?)?$' + CANONICAL = '%Y-%m-%dT%H:%M:%S' + + def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + value = str(value) + match = re.match(Timestamp.REGULAR_SHORT, value) + if match is not None: + # Parse short form + year = int(match.group('year')) + month = int(match.group('month')) + day = int(match.group('day')) + self.value = datetime(year, month, day, tzinfo=UTC) + else: + match = re.match(Timestamp.REGULAR_LONG, value) + if match is not None: + # Parse long form + year = int(match.group('year')) + month = int(match.group('month')) + day = int(match.group('day')) + hour = match.group('hour') + if hour is not None: + hour = int(hour) + minute = match.group('minute') + if minute is not None: + minute = int(minute) + second = match.group('second') + if second is not None: + second = int(second) + fraction = match.group('fraction') + if fraction is not None: + fraction = int(float(fraction) * 1000000.0) # convert to microseconds + tzhour = match.group('tzhour') + if tzhour is not None: + tzhour = int(tzhour) + else: + tzhour = 0 + tzminute = match.group('tzminute') + if tzminute is not None: + tzminute = int(tzminute) + else: + tzminute = 0 + self.value = datetime(year, month, day, hour, minute, second, fraction, + Timezone(tzhour, tzminute)) + else: + raise ValueError( + 'timestamp must be formatted as YAML ISO8601 variant or "YYYY-MM-DD": %s' + % safe_repr(value)) + + @property + def as_datetime_utc(self): + return self.value.astimezone(UTC) + + @property + def as_raw(self): + return self.__str__() + + def __str__(self): + the_datetime = self.as_datetime_utc + return '%s%sZ' \ + % (the_datetime.strftime(Timestamp.CANONICAL), Timestamp._fraction_as_str(the_datetime)) + + def __repr__(self): + return repr(self.__str__()) + + def __eq__(self, timestamp): + if not isinstance(timestamp, Timestamp): + return False + return self.value == timestamp.value + + def __lt__(self, timestamp): + return self.value < timestamp.value + + @staticmethod + def _fraction_as_str(the_datetime): + return '{0:g}'.format(the_datetime.microsecond / 1000000.0).lstrip('0') + + +@total_ordering +@implements_specification('3.2.2', 'tosca-simple-1.0') +class Version(object): + """ + TOSCA supports the concept of "reuse" of type definitions, as well as template definitions which + could be version and change over time. It is important to provide a reliable, normative means to + represent a version string which enables the comparison and management of types and templates + over time. Therefore, the TOSCA TC intends to provide a normative version type (string) for this + purpose in future Working Drafts of this specification. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_VERSION>`__ + """ + + REGEX = \ + r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<fix>\d+)' + \ + r'((\.(?P<qualifier>\d+))(\-(?P<build>\d+))?)?)?$' + + @staticmethod + def key(version): + """ + Key method for fast sorting. + """ + return (version.major, version.minor, version.fix, version.qualifier, version.build) + + def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + str_value = str(value) + match = re.match(Version.REGEX, str_value) + if match is None: + raise ValueError( + 'version must be formatted as <major_version>.<minor_version>' + '[.<fix_version>[.<qualifier>[-<build_version]]]: %s' + % safe_repr(value)) + + self.value = str_value + + self.major = match.group('major') + self.major = int(self.major) + self.minor = match.group('minor') + self.minor = int(self.minor) + self.fix = match.group('fix') + if self.fix is not None: + self.fix = int(self.fix) + self.qualifier = match.group('qualifier') + if self.qualifier is not None: + self.qualifier = int(self.qualifier) + self.build = match.group('build') + if self.build is not None: + self.build = int(self.build) + + @property + def as_raw(self): + return self.value + + def __str__(self): + return self.value + + def __repr__(self): + return repr(self.__str__()) + + def __eq__(self, version): + if not isinstance(version, Version): + return False + return (self.major, self.minor, self.fix, self.qualifier, self.build) == \ + (version.major, version.minor, version.fix, version.qualifier, version.build) + + def __lt__(self, version): + if self.major < version.major: + return True + elif self.major == version.major: + if self.minor < version.minor: + return True + elif self.minor == version.minor: + if self.fix < version.fix: + return True + elif self.fix == version.fix: + if self.qualifier < version.qualifier: + return True + elif self.qualifier == version.qualifier: + if self.build < version.build: + return True + return False + + +@implements_specification('3.2.3', 'tosca-simple-1.0') +class Range(object): + """ + The range type can be used to define numeric ranges with a lower and upper boundary. For + example, this allows for specifying a range of ports to be opened in a firewall. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_RANGE>`__ + """ + + def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + if not isinstance(value, list): + raise ValueError('range value is not a list: %s' % safe_repr(value)) + if len(value) != 2: + raise ValueError('range value does not have exactly 2 elements: %s' % safe_repr(value)) + + def is_int(v): + return isinstance(v, int) and (not isinstance(v, bool)) # In Python bool is an int + + if not is_int(value[0]): + raise ValueError('lower bound of range is not a valid integer: %s' + % safe_repr(value[0])) + + if value[1] != 'UNBOUNDED': + if not is_int(value[1]): + raise ValueError('upper bound of range is not a valid integer or "UNBOUNDED": %s' + % safe_repr(value[0])) + + if value[0] >= value[1]: + raise ValueError( + 'upper bound of range is not greater than the lower bound: %s >= %s' + % (safe_repr(value[0]), safe_repr(value[1]))) + + self.value = value + + def is_in(self, value): + if value < self.value[0]: + return False + if (self.value[1] != 'UNBOUNDED') and (value > self.value[1]): + return False + return True + + @property + def as_raw(self): + return list(self.value) + + +@implements_specification('3.2.4', 'tosca-simple-1.0') +class List(list): + """ + The list type allows for specifying multiple values for a parameter of property. For example, if + an application allows for being configured to listen on multiple ports, a list of ports could be + configured using the list data type. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_LIST>`__ + """ + + @staticmethod + def _create(context, presentation, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + if not isinstance(value, list): + raise ValueError('"list" data type value is not a list: %s' % safe_repr(value)) + + entry_schema_type = entry_schema._get_type(context) + entry_schema_constraints = entry_schema.constraints + + the_list = List() + for v in value: + v = coerce_value(context, presentation, entry_schema_type, None, + entry_schema_constraints, v, aspect) + if v is not None: + the_list.append(v) + + return the_list + + # Can't define as property because it's old-style Python class + def as_raw(self): + return list(self) + + +@implements_specification('3.2.5', 'tosca-simple-1.0') +class Map(StrictDict): + """ + The map type allows for specifying multiple values for a parameter of property as a map. In + contrast to the list type, where each entry can only be addressed by its index in the list, + entries in a map are named elements that can be addressed by their keys. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_MAP>`__ + """ + + @staticmethod + def _create(context, presentation, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + if not isinstance(value, dict): + raise ValueError('"map" data type value is not a dict: %s' % safe_repr(value)) + + if entry_schema is None: + raise ValueError('"map" data type does not define "entry_schema"') + + entry_schema_type = entry_schema._get_type(context) + entry_schema_constraints = entry_schema.constraints + + the_map = Map() + for k, v in value.iteritems(): + v = coerce_value(context, presentation, entry_schema_type, None, + entry_schema_constraints, v, aspect) + if v is not None: + the_map[k] = v + + return the_map + + def __init__(self, items=None): + super(Map, self).__init__(items, key_class=str) + + # Can't define as property because it's old-style Python class + def as_raw(self): + return OrderedDict(self) + + +@total_ordering +@implements_specification('3.2.6', 'tosca-simple-1.0') +class Scalar(object): + """ + The scalar-unit type can be used to define scalar values along with a unit from the list of + recognized units. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_SCALAR_UNIT>`__ + """ + + @staticmethod + def key(scalar): + """ + Key method for fast sorting. + """ + return scalar.value + + def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + str_value = str(value) + match = re.match(self.REGEX, str_value) # pylint: disable=no-member + if match is None: + raise ValueError('scalar must be formatted as <scalar> <unit>: %s' % safe_repr(value)) + + self.factor = float(match.group('scalar')) + if self.factor < 0: + raise ValueError('scalar is negative: %s' % safe_repr(self.factor)) + + self.unit = match.group('unit') + + unit_lower = self.unit.lower() + unit_size = None + for k, v in self.UNITS.iteritems(): # pylint: disable=no-member + if k.lower() == unit_lower: + self.unit = k + unit_size = v + break + if unit_size is None: + raise ValueError('scalar specified with unsupported unit: %s' % safe_repr(self.unit)) + + self.value = self.TYPE(self.factor * unit_size) # pylint: disable=no-member + + @property + def as_raw(self): + return OrderedDict(( + ('value', self.value), + ('factor', self.factor), + ('unit', self.unit), + ('unit_size', self.UNITS[self.unit]))) # pylint: disable=no-member + + def __str__(self): + return '%s %s' % (self.value, self.UNIT) # pylint: disable=no-member + + def __repr__(self): + return repr(self.__str__()) + + def __eq__(self, scalar): + if isinstance(scalar, Scalar): + value = scalar.value + else: + value = self.TYPE(scalar) # pylint: disable=no-member + return self.value == value + + def __lt__(self, scalar): + if isinstance(scalar, Scalar): + value = scalar.value + else: + value = self.TYPE(scalar) # pylint: disable=no-member + return self.value < value + + +@implements_specification('3.2.6.4', 'tosca-simple-1.0') +class ScalarSize(Scalar): + """ + Integer scalar for counting bytes. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_SCALAR_UNIT_SIZE>`__ + """ + + # See: http://www.regular-expressions.info/floatingpoint.html + REGEX = \ + r'^(?P<scalar>[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\s*(?P<unit>B|kB|KiB|MB|MiB|GB|GiB|TB|TiB)$' + + UNITS = { + 'B': 1, + 'kB': 1000, + 'KiB': 1024, + 'MB': 1000000, + 'MiB': 1048576, + 'GB': 1000000000, + 'GiB': 1073741824, + 'TB': 1000000000000, + 'TiB': 1099511627776} + + TYPE = int + UNIT = 'bytes' + + +@implements_specification('3.2.6.5', 'tosca-simple-1.0') +class ScalarTime(Scalar): + """ + Floating point scalar for counting seconds. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_SCALAR_UNIT_TIME>`__ + """ + + # See: http://www.regular-expressions.info/floatingpoint.html + REGEX = r'^(?P<scalar>[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\s*(?P<unit>ns|us|ms|s|m|h|d)$' + + UNITS = { + 'ns': 0.000000001, + 'us': 0.000001, + 'ms': 0.001, + 's': 1.0, + 'm': 60.0, + 'h': 3600.0, + 'd': 86400.0} + + TYPE = float + UNIT = 'seconds' + + +@implements_specification('3.2.6.6', 'tosca-simple-1.0') +class ScalarFrequency(Scalar): + """ + Floating point scalar for counting cycles per second (Hz). + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #TYPE_TOSCA_SCALAR_UNIT_FREQUENCY>`__ + """ + + # See: http://www.regular-expressions.info/floatingpoint.html + REGEX = r'^(?P<scalar>[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\s*(?P<unit>Hz|kHz|MHz|GHz)$' + + UNITS = { + 'Hz': 1.0, + 'kHz': 1000.0, + 'MHz': 1000000.0, + 'GHz': 1000000000.0} + + TYPE = float + UNIT = 'Hz' + + +# +# The following are hooked in the YAML as 'coerce_value' extensions +# + +def coerce_timestamp(context, presentation, the_type, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + return coerce_to_data_type_class(context, presentation, Timestamp, entry_schema, constraints, + value, aspect) + + +def coerce_version(context, presentation, the_type, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + return coerce_to_data_type_class(context, presentation, Version, entry_schema, constraints, + value, aspect) + + +def coerce_range(context, presentation, the_type, entry_schema, constraints, value, aspect): + if aspect == 'in_range': + # When we're in a "in_range" constraint, the values are *not* themselves ranges, but numbers + try: + return float(value) + except ValueError as e: + report_issue_for_bad_format(context, presentation, the_type, value, aspect, e) + except TypeError as e: + report_issue_for_bad_format(context, presentation, the_type, value, aspect, e) + else: + return coerce_to_data_type_class(context, presentation, Range, entry_schema, constraints, + value, aspect) + + +def coerce_list(context, presentation, the_type, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + return coerce_to_data_type_class(context, presentation, List, entry_schema, constraints, + value, aspect) + + +def coerce_map_value(context, presentation, the_type, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument + return coerce_to_data_type_class(context, presentation, Map, entry_schema, constraints, value, + aspect) + + +def coerce_scalar_unit_size(context, presentation, the_type, entry_schema, constraints, value, # pylint: disable=unused-argument + aspect): + return coerce_to_data_type_class(context, presentation, ScalarSize, entry_schema, constraints, + value, aspect) + + +def coerce_scalar_unit_time(context, presentation, the_type, entry_schema, constraints, value, # pylint: disable=unused-argument + aspect): + return coerce_to_data_type_class(context, presentation, ScalarTime, entry_schema, constraints, + value, aspect) + + +def coerce_scalar_unit_frequency(context, presentation, the_type, entry_schema, constraints, value, # pylint: disable=unused-argument + aspect): + return coerce_to_data_type_class(context, presentation, ScalarFrequency, entry_schema, + constraints, value, aspect) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/definitions.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/definitions.py new file mode 100644 index 0000000..9158776 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/definitions.py @@ -0,0 +1,518 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import FrozenDict +from aria.utils.caching import cachedmethod +from aria.parser import implements_specification +from aria.parser.presentation import (has_fields, short_form_field, allow_unknown_fields, + primitive_field, primitive_list_field, object_field, + object_list_field, object_dict_field, + object_dict_unknown_fields, field_validator, + field_getter, type_validator, list_type_validator) + +from .data_types import Range +from .misc import (Description, ConstraintClause, OperationImplementation, EntrySchema) +from .presentation.extensible import ExtensiblePresentation +from .presentation.field_getters import data_type_class_getter +from .presentation.field_validators import (data_type_validator, data_value_validator, + entry_schema_validator) +from .presentation.types import (convert_name_to_full_type_name, get_type_by_name) +from .modeling.data_types import get_data_type, get_property_constraints +from .modeling.interfaces import (get_and_override_input_definitions_from_type, + get_and_override_operation_definitions_from_type) + + +@has_fields +@implements_specification('3.5.8', 'tosca-simple-1.0') +class PropertyDefinition(ExtensiblePresentation): + """ + A property definition defines a named, typed value and related data that can be associated with + an entity defined in this specification (e.g., Node Types, Relationship Types, Capability Types, + etc.). Properties are used by template authors to provide input values to TOSCA entities which + indicate their "desired state" when they are instantiated. The value of a property can be + retrieved using the ``get_property`` function within TOSCA Service Templates. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_PROPERTY_DEFN>`__ + """ + + @field_validator(data_type_validator()) + @primitive_field(str, required=True) + def type(self): + """ + The required data type for the property. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the property. + + :type: :class:`Description` + """ + + @primitive_field(bool, default=True) + def required(self): + """ + An optional key that declares a property as required (true) or not (false). + + :type: bool + """ + + @field_validator(data_value_validator) + @primitive_field() + def default(self): + """ + An optional key that may provide a value to be used as a default if not provided by another + means. + + :type: :obj:`basestring` + """ + + @primitive_field(str, default='supported', allowed=('supported', 'unsupported', 'experimental', + 'deprecated')) + @implements_specification(section='3.5.8.3', spec='tosca-simple-1.0') + def status(self): + """ + The optional status of the property relative to the specification or implementation. + + :type: :obj:`basestring` + """ + + @object_list_field(ConstraintClause) + def constraints(self): + """ + The optional list of sequenced constraint clauses for the property. + + :type: list of (str, :class:`ConstraintClause`) + """ + + @field_validator(entry_schema_validator) + @object_field(EntrySchema) + def entry_schema(self): + """ + The optional key that is used to declare the name of the Datatype definition for entries of + set types such as the TOSCA list or map. + + :type: :obj:`basestring` + """ + + @cachedmethod + def _get_type(self, context): + return get_data_type(context, self, 'type') + + @cachedmethod + def _get_constraints(self, context): + return get_property_constraints(context, self) + + +@has_fields +@implements_specification('3.5.10', 'tosca-simple-1.0') +class AttributeDefinition(ExtensiblePresentation): + """ + An attribute definition defines a named, typed value that can be associated with an entity + defined in this specification (e.g., a Node, Relationship or Capability Type). Specifically, it + is used to expose the "actual state" of some property of a TOSCA entity after it has been + deployed and instantiated (as set by the TOSCA orchestrator). Attribute values can be retrieved + via the ``get_attribute`` function from the instance model and used as values to other + entities within TOSCA Service Templates. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_ATTRIBUTE_DEFN>`__ + """ + + @field_validator(data_type_validator()) + @primitive_field(str, required=True) + def type(self): + """ + The required data type for the attribute. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the attribute. + + :type: :class:`Description` + """ + + @field_validator(data_value_validator) + @primitive_field() + def default(self): + """ + An optional key that may provide a value to be used as a default if not provided by another + means. + + This value SHALL be type compatible with the type declared by the property definition's type + keyname. + + :type: :obj:`basestring` + """ + + @primitive_field(str, default='supported', allowed=('supported', 'unsupported', 'experimental', + 'deprecated')) + def status(self): + """ + The optional status of the attribute relative to the specification or implementation. + + :type: :obj:`basestring` + """ + + @field_validator(entry_schema_validator) + @object_field(EntrySchema) + def entry_schema(self): + """ + The optional key that is used to declare the name of the Datatype definition for entries of + set types such as the TOSCA list or map. + + :type: :obj:`basestring` + """ + + @cachedmethod + def _get_type(self, context): + return get_data_type(context, self, 'type') + + +@has_fields +@implements_specification('3.5.12', 'tosca-simple-1.0') +class ParameterDefinition(PropertyDefinition): + """ + A parameter definition is essentially a TOSCA property definition; however, it also allows a + value to be assigned to it (as for a TOSCA property assignment). In addition, in the case of + output parameters, it can optionally inherit the data type of the value assigned to it rather + than have an explicit data type defined for it. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_PARAMETER_DEF>`__ + """ + + @field_validator(data_type_validator()) + @primitive_field(str) + def type(self): + """ + The required data type for the parameter. + + Note: This keyname is required for a TOSCA Property definition, but is not for a TOSCA + Parameter definition. + + :type: :obj:`basestring` + """ + + @field_validator(data_value_validator) + @primitive_field() + def value(self): + """ + The type-compatible value to assign to the named parameter. Parameter values may be provided + as the result from the evaluation of an expression or a function. + """ + + +@short_form_field('implementation') +@has_fields +@implements_specification('3.5.13-1', 'tosca-simple-1.0') +class OperationDefinition(ExtensiblePresentation): + """ + An operation definition defines a named function or procedure that can be bound to an + implementation artifact (e.g., a script). + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_OPERATION_DEF>`__ + """ + + @object_field(Description) + def description(self): + """ + The optional description string for the associated named operation. + + :type: :class:`Description` + """ + + @object_field(OperationImplementation) + def implementation(self): + """ + The optional implementation artifact name (e.g., a script file name within a TOSCA CSAR + file). + + :type: :class:`OperationImplementation` + """ + + @object_dict_field(PropertyDefinition) + def inputs(self): + """ + The optional list of input property definitions available to all defined operations for + interface definitions that are within TOSCA Node or Relationship Type definitions. This + includes when interface definitions are included as part of a Requirement definition in a + Node Type. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + +@allow_unknown_fields +@has_fields +@implements_specification('3.5.14-1', 'tosca-simple-1.0') +class InterfaceDefinition(ExtensiblePresentation): + """ + An interface definition defines a named interface that can be associated with a Node or + Relationship Type. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_INTERFACE_DEF>`__ + """ + + @field_validator(type_validator('interface type', convert_name_to_full_type_name, + 'interface_types')) + @primitive_field(str) + def type(self): + """ + ARIA NOTE: This field is not mentioned in the spec, but is implied. + + :type: :obj:`basestring` + """ + + @object_dict_field(PropertyDefinition) + def inputs(self): + """ + The optional list of input property definitions available to all defined operations for + interface definitions that are within TOSCA Node or Relationship Type definitions. This + includes when interface definitions are included as part of a Requirement definition in a + Node Type. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @object_dict_unknown_fields(OperationDefinition) + def operations(self): + """ + :type: {:obj:`basestring`: :class:`OperationDefinition`} + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'interface_types') + + @cachedmethod + def _get_inputs(self, context): + return FrozenDict(get_and_override_input_definitions_from_type(context, self)) + + @cachedmethod + def _get_operations(self, context): + return FrozenDict(get_and_override_operation_definitions_from_type(context, self)) + + def _validate(self, context): + super(InterfaceDefinition, self)._validate(context) + if self.operations: + for operation in self.operations.itervalues(): # pylint: disable=no-member + operation._validate(context) + + +@short_form_field('type') +@has_fields +class RelationshipDefinition(ExtensiblePresentation): + """ + Relationship definition. + """ + + @field_validator(type_validator('relationship type', convert_name_to_full_type_name, + 'relationship_types')) + @primitive_field(str, required=True) + def type(self): + """ + The optional reserved keyname used to provide the name of the Relationship Type for the + requirement definition's relationship keyname. + + :type: :obj:`basestring` + """ + + @object_dict_field(InterfaceDefinition) + def interfaces(self): + """ + The optional reserved keyname used to reference declared (named) interface definitions of + the corresponding Relationship Type in order to declare additional Property definitions for + these interfaces or operations of these interfaces. + + :type: list of :class:`InterfaceDefinition` + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'relationship_types') + + + +@short_form_field('capability') +@has_fields +@implements_specification('3.6.2', 'tosca-simple-1.0') +class RequirementDefinition(ExtensiblePresentation): + """ + The Requirement definition describes a named requirement (dependencies) of a TOSCA Node Type or + Node template which needs to be fulfilled by a matching Capability definition declared by + another TOSCA modelable entity. The requirement definition may itself include the specific name + of the fulfilling entity (explicitly) or provide an abstract type, along with additional + filtering characteristics, that a TOSCA orchestrator can use to fulfill the capability at + runtime (implicitly). + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_REQUIREMENT_DEF>`__ + """ + + @field_validator(type_validator('capability type', convert_name_to_full_type_name, + 'capability_types')) + @primitive_field(str, required=True) + def capability(self): + """ + The required reserved keyname used that can be used to provide the name of a valid + Capability Type that can fulfill the requirement. + + :type: :obj:`basestring` + """ + + @field_validator(type_validator('node type', convert_name_to_full_type_name, + 'node_types')) + @primitive_field(str) + def node(self): + """ + The optional reserved keyname used to provide the name of a valid Node Type that contains + the capability definition that can be used to fulfill the requirement. + + :type: :obj:`basestring` + """ + + @object_field(RelationshipDefinition) + def relationship(self): + """ + The optional reserved keyname used to provide the name of a valid Relationship Type to + construct when fulfilling the requirement. + + :type: :class:`RelationshipDefinition` + """ + + @field_getter(data_type_class_getter(Range)) + @primitive_field() + def occurrences(self): + """ + The optional minimum and maximum occurrences for the requirement. + + Note: the keyword UNBOUNDED is also supported to represent any positive integer. + + :type: :class:`Range` + """ + + @cachedmethod + def _get_capability_type(self, context): + return get_type_by_name(context, self.capability, 'capability_types') + + @cachedmethod + def _get_node_type(self, context): + return context.presentation.get_from_dict('service_template', 'node_types', self.node) + + +@short_form_field('type') +@has_fields +@implements_specification('3.6.1', 'tosca-simple-1.0') +class CapabilityDefinition(ExtensiblePresentation): + """ + A capability definition defines a named, typed set of data that can be associated with Node Type + or Node Template to describe a transparent capability or feature of the software component the + node describes. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_CAPABILITY_DEFN>`__ + """ + + @field_validator(type_validator('capability type', convert_name_to_full_type_name, + 'capability_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the Capability Type the capability definition is based upon. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + The optional description of the Capability definition. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyDefinition) + def properties(self): + """ + An optional list of property definitions for the Capability definition. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @object_dict_field(AttributeDefinition) + def attributes(self): + """ + An optional list of attribute definitions for the Capability definition. + + :type: {:obj:`basestring`: :class:`AttributeDefinition`} + """ + + @field_validator(list_type_validator('node type', convert_name_to_full_type_name, + 'node_types')) + @primitive_list_field(str) + def valid_source_types(self): + """ + An optional list of one or more valid names of Node Types that are supported as valid + sources of any relationship established to the declared Capability Type. + + :type: [:obj:`basestring`] + """ + + @field_getter(data_type_class_getter(Range)) + @primitive_field() + def occurrences(self): + """ + The optional minimum and maximum occurrences for the capability. By default, an exported + Capability should allow at least one relationship to be formed with it with a maximum of + ``UNBOUNDED`` relationships. + + Note: the keyword ``UNBOUNDED`` is also supported to represent any positive integer. + + ARIA NOTE: The spec seems wrong here: the implied default should be ``[0,UNBOUNDED]``, not + ``[1,UNBOUNDED]``, otherwise it would imply that at 1 least one relationship *must* be + formed. + + :type: :class:`Range` + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'capability_types') + + @cachedmethod + def _get_parent(self, context): + container_parent = self._container._get_parent(context) + container_parent_capabilities = container_parent._get_capabilities(context) \ + if container_parent is not None else None + return container_parent_capabilities.get(self._name) \ + if container_parent_capabilities is not None else None diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/filters.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/filters.py new file mode 100644 index 0000000..95d84b2 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/filters.py @@ -0,0 +1,107 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.caching import cachedmethod +from aria.parser import implements_specification +from aria.parser.presentation import (has_fields, object_sequenced_list_field, field_validator) + +from .misc import ConstraintClause +from .presentation.extensible import ExtensiblePresentation +from .presentation.field_validators import (node_filter_properties_validator, + node_filter_capabilities_validator) + + +@has_fields +class CapabilityFilter(ExtensiblePresentation): + """ + Capability filter. + """ + + @object_sequenced_list_field(ConstraintClause) + def properties(self): + pass + + @cachedmethod + def _get_node_type(self, context): + return self._container._get_node_type(context) + + @cachedmethod + def _get_type_for_name(self, context, name): + node_type = self._get_node_type(context) + if node_type is not None: + capabilities = node_type._get_capabilities(context) + capability = capabilities.get(self._name) + properties = capability.properties if capability is not None else None + prop = properties.get(name) if properties is not None else None + return prop._get_type(context) if prop is not None else None + + return None + + +@has_fields +@implements_specification('3.5.4', 'tosca-simple-1.0') +class NodeFilter(ExtensiblePresentation): + """ + A node filter definition defines criteria for selection of a TOSCA Node Template based upon the + template's property values, capabilities and capability properties. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_NODE_FILTER_DEFN>`__ + """ + + @field_validator(node_filter_properties_validator) + @object_sequenced_list_field(ConstraintClause) + @implements_specification('3.5.3', 'tosca-simple-1.0') + def properties(self): + """ + An optional sequenced list of property filters that would be used to select (filter) + matching TOSCA entities (e.g., Node Template, Node Type, Capability Types, etc.) based upon + their property definitions' values. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_PROPERTY_FILTER_DEFN>`__ + + :type: list of (str, :class:`ConstraintClause`) + """ + + @field_validator(node_filter_capabilities_validator) + @object_sequenced_list_field(CapabilityFilter) + def capabilities(self): + """ + An optional sequenced list of property filters that would be used to select (filter) + matching TOSCA entities (e.g., Node Template, Node Type, Capability Types, etc.) based upon + their capabilities' property definitions' values. + + :type: list of (str, :class:`CapabilityDefinition`) + """ + + @cachedmethod + def _get_node_type(self, context): + if hasattr(self._container, '_get_node'): + node_type, node_type_variant = self._container._get_node(context) + return node_type if node_type_variant == 'node_type' else None + return None + + @cachedmethod + def _get_type_for_name(self, context, name): + node_type = self._get_node_type(context) + if node_type is not None: + properties = node_type._get_properties(context) + prop = properties.get(name) + return prop._get_type(context) if prop is not None else None + + return None diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/misc.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/misc.py new file mode 100644 index 0000000..221163c --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/misc.py @@ -0,0 +1,444 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.caching import cachedmethod +from aria.utils.console import puts +from aria.utils.formatting import as_raw +from aria.parser import implements_specification +from aria.parser.presentation import (AsIsPresentation, has_fields, allow_unknown_fields, + short_form_field, primitive_field, primitive_list_field, + primitive_dict_unknown_fields, object_field, + object_list_field, object_dict_field, field_validator, + type_validator) + +from .modeling.data_types import (get_data_type, get_data_type_value, get_property_constraints, + apply_constraint_to_value) +from .modeling.substitution_mappings import (validate_substitution_mappings_requirement, + validate_substitution_mappings_capability) +from .presentation.extensible import ExtensiblePresentation +from .presentation.field_validators import (constraint_clause_field_validator, + constraint_clause_in_range_validator, + constraint_clause_valid_values_validator, + constraint_clause_pattern_validator, + data_type_validator) +from .presentation.types import (convert_name_to_full_type_name, get_type_by_name) + + + +@implements_specification('3.5.1', 'tosca-simple-1.0') +class Description(AsIsPresentation): + """ + Human-readable description. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_DESCRIPTION>`__ + """ + + def __init__(self, name=None, raw=None, container=None, cls=None): # pylint: disable=unused-argument + super(Description, self).__init__(name, raw, container, cls=unicode) + + def _dump(self, context): + value = as_raw(self.value) + puts(context.style.meta_style(value)) + + +@allow_unknown_fields +@has_fields +@implements_specification('3.9.3.2', 'tosca-simple-1.0') +class MetaData(ExtensiblePresentation): + """ + Meta data. + """ + + @primitive_field(str) + @implements_specification('3.9.3.3', 'tosca-simple-1.0') + def template_name(self): + """ + This optional metadata keyname can be used to declare the name of service template as a + single-line string value. + """ + + @primitive_field(str) + @implements_specification('3.9.3.4', 'tosca-simple-1.0') + def template_author(self): + """ + This optional metadata keyname can be used to declare the author(s) of the service template + as a single-line string value. + """ + + @primitive_field(str) + @implements_specification('3.9.3.5', 'tosca-simple-1.0') + def template_version(self): + """ + This optional metadata keyname can be used to declare a domain specific version of the + service template as a single-line string value. + """ + + @primitive_dict_unknown_fields() + def custom(self): + """ + :type: dict + """ + + +@short_form_field('url') +@has_fields +@implements_specification('3.5.5', 'tosca-simple-1.0') +class Repository(ExtensiblePresentation): + """ + A repository definition defines a named external repository which contains deployment and + implementation artifacts that are referenced within the TOSCA Service Template. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_REPOSITORY_DEF>`__ + """ + + @object_field(Description) + def description(self): + """ + The optional description for the repository. + + :type: :class:`Description` + """ + + @primitive_field(str, required=True) + def url(self): + """ + The required URL or network address used to access the repository. + + :type: :obj:`basestring` + """ + + @primitive_field() + def credential(self): + """ + The optional Credential used to authorize access to the repository. + + :type: tosca.datatypes.Credential + """ + + @cachedmethod + def _get_credential(self, context): + return get_data_type_value(context, self, 'credential', 'tosca.datatypes.Credential') + + +@short_form_field('file') +@has_fields +@implements_specification('3.5.7', 'tosca-simple-1.0') +class Import(ExtensiblePresentation): + """ + An import definition is used within a TOSCA Service Template to locate and uniquely name another + TOSCA Service Template file which has type and template definitions to be imported (included) + and referenced within another Service Template. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_IMPORT_DEF>`__ + """ + + @primitive_field(str, required=True) + def file(self): + """ + The required symbolic name for the imported file. + + :type: :obj:`basestring` + """ + + @primitive_field(str) + def repository(self): + """ + The optional symbolic name of the repository definition where the imported file can be found + as a string. + + :type: :obj:`basestring` + """ + + @primitive_field(str) + def namespace_uri(self): + """ + The optional namespace URI to that will be applied to type definitions found within the + imported file as a string. + + :type: :obj:`basestring` + """ + + @primitive_field(str) + def namespace_prefix(self): + """ + The optional namespace prefix (alias) that will be used to indicate the namespace_uri when + forming a qualified name (i.e., qname) when referencing type definitions from the imported + file. + + :type: :obj:`basestring` + """ + + +@has_fields +@implements_specification('3.5.2-1', 'tosca-simple-1.0') +class ConstraintClause(ExtensiblePresentation): + """ + A constraint clause defines an operation along with one or more compatible values that can be + used to define a constraint on a property or parameter's allowed values when it is defined in a + TOSCA Service Template or one of its entities. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_CONSTRAINTS_CLAUSE>`__ + """ + + @field_validator(constraint_clause_field_validator) + @primitive_field() + def equal(self): + """ + Constrains a property or parameter to a value equal to ('=') the value declared. + """ + + @field_validator(constraint_clause_field_validator) + @primitive_field() + def greater_than(self): + """ + Constrains a property or parameter to a value greater than ('>') the value declared. + """ + + @field_validator(constraint_clause_field_validator) + @primitive_field() + def greater_or_equal(self): + """ + Constrains a property or parameter to a value greater than or equal to ('>=') the value + declared. + """ + + @field_validator(constraint_clause_field_validator) + @primitive_field() + def less_than(self): + """ + Constrains a property or parameter to a value less than ('<') the value declared. + """ + + @field_validator(constraint_clause_field_validator) + @primitive_field() + def less_or_equal(self): + """ + Constrains a property or parameter to a value less than or equal to ('<=') the value + declared. + """ + + @field_validator(constraint_clause_in_range_validator) + @primitive_list_field() + def in_range(self): + """ + Constrains a property or parameter to a value in range of (inclusive) the two values + declared. + + Note: subclasses or templates of types that declare a property with the ``in_range`` + constraint MAY only further restrict the range specified by the parent type. + """ + + @field_validator(constraint_clause_valid_values_validator) + @primitive_list_field() + def valid_values(self): + """ + Constrains a property or parameter to a value that is in the list of declared values. + """ + + @primitive_field(int) + def length(self): + """ + Constrains the property or parameter to a value of a given length. + """ + + @primitive_field(int) + def min_length(self): + """ + Constrains the property or parameter to a value to a minimum length. + """ + + @primitive_field(int) + def max_length(self): + """ + Constrains the property or parameter to a value to a maximum length. + """ + + @field_validator(constraint_clause_pattern_validator) + @primitive_field(str) + def pattern(self): + """ + Constrains the property or parameter to a value that is allowed by the provided regular + expression. + + Note: Future drafts of this specification will detail the use of regular expressions and + reference an appropriate standardized grammar. + """ + + @cachedmethod + def _get_type(self, context): + if hasattr(self._container, '_get_type_for_name'): + # NodeFilter or CapabilityFilter + return self._container._get_type_for_name(context, self._name) + elif hasattr(self._container, '_get_type'): + # Properties + return self._container._get_type(context) + else: + # DataType (the DataType itself is our type) + return self._container + + def _apply_to_value(self, context, presentation, value): + return apply_constraint_to_value(context, presentation, self, value) + + +@short_form_field('type') +@has_fields +class EntrySchema(ExtensiblePresentation): + """ + ARIA NOTE: The specification does not properly explain this type, however it is implied by + examples. + """ + + @field_validator(data_type_validator('entry schema data type')) + @primitive_field(str, required=True) + def type(self): + """ + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + :type: :class:`Description` + """ + + @object_list_field(ConstraintClause) + def constraints(self): + """ + :type: list of (str, :class:`ConstraintClause`) + """ + + @cachedmethod + def _get_type(self, context): + return get_data_type(context, self, 'type') + + @cachedmethod + def _get_constraints(self, context): + return get_property_constraints(context, self) + + +@short_form_field('primary') +@has_fields +class OperationImplementation(ExtensiblePresentation): + """ + Operation implementation. + """ + + @primitive_field(str) + def primary(self): + """ + The optional implementation artifact name (i.e., the primary script file name within a + TOSCA CSAR file). + + :type: :obj:`basestring` + """ + + @primitive_list_field(str) + def dependencies(self): + """ + The optional ordered list of one or more dependent or secondary implementation artifact name + which are referenced by the primary implementation artifact (e.g., a library the script + installs or a secondary script). + + :type: [:obj:`basestring`] + """ + + +class SubstitutionMappingsRequirement(AsIsPresentation): + """ + Substitution mapping for requirement. + """ + + @property + @cachedmethod + def node_template(self): + return str(self._raw[0]) + + @property + @cachedmethod + def requirement(self): + return str(self._raw[1]) + + def _validate(self, context): + super(SubstitutionMappingsRequirement, self)._validate(context) + validate_substitution_mappings_requirement(context, self) + + +class SubstitutionMappingsCapability(AsIsPresentation): + """ + Substitution mapping for capability. + """ + + @property + @cachedmethod + def node_template(self): + return str(self._raw[0]) + + @property + @cachedmethod + def capability(self): + return str(self._raw[1]) + + def _validate(self, context): + super(SubstitutionMappingsCapability, self)._validate(context) + validate_substitution_mappings_capability(context, self) + + +@has_fields +@implements_specification('2.10', 'tosca-simple-1.0') +class SubstitutionMappings(ExtensiblePresentation): + """ + Substitution mappings. + """ + + @field_validator(type_validator('node type', convert_name_to_full_type_name, 'node_types')) + @primitive_field(str, required=True) + def node_type(self): + """ + :type: :obj:`basestring` + """ + + @object_dict_field(SubstitutionMappingsRequirement) + def requirements(self): + """ + :type: {:obj:`basestring`: :class:`SubstitutionMappingsRequirement`} + """ + + @object_dict_field(SubstitutionMappingsCapability) + def capabilities(self): + """ + :type: {:obj:`basestring`: :class:`SubstitutionMappingsCapability`} + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.node_type, 'node_types') + + def _validate(self, context): + super(SubstitutionMappings, self)._validate(context) + self._get_type(context) + + def _dump(self, context): + self._dump_content(context, ( + 'node_type', + 'requirements', + 'capabilities')) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py new file mode 100644 index 0000000..d960e05 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py @@ -0,0 +1,750 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Creates ARIA service template models based on the TOSCA presentation. + +Relies on many helper methods in the presentation classes. +""" + +#pylint: disable=unsubscriptable-object + +import os +import re +from types import FunctionType +from datetime import datetime + +from ruamel import yaml + +from aria.parser.validation import Issue +from aria.utils.formatting import string_list_as_string +from aria.utils.collections import (StrictDict, OrderedDict) +from aria.orchestrator import WORKFLOW_DECORATOR_RESERVED_ARGUMENTS +from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate, + RequirementTemplate, RelationshipTemplate, CapabilityTemplate, + GroupTemplate, PolicyTemplate, SubstitutionTemplate, + SubstitutionTemplateMapping, InterfaceTemplate, OperationTemplate, + ArtifactTemplate, Metadata, Input, Output, Property, + Attribute, Configuration, PluginSpecification) + +from .parameters import coerce_parameter_value +from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, InRange, + ValidValues, Length, MinLength, MaxLength, Pattern) +from ..data_types import coerce_value + + +# These match the first un-escaped ">" +# See: http://stackoverflow.com/a/11819111/849021 +IMPLEMENTATION_PREFIX_REGEX = re.compile(r'(?<!\\)(?:\\\\)*>') + + +def create_service_template_model(context): # pylint: disable=too-many-locals,too-many-branches + model = ServiceTemplate(created_at=datetime.now(), + main_file_name=os.path.basename(str(context.presentation.location))) + + model.description = context.presentation.get('service_template', 'description', 'value') + + # Metadata + metadata = context.presentation.get('service_template', 'metadata') + if metadata is not None: + create_metadata_models(context, model, metadata) + + # Types + model.node_types = Type(variant='node') + create_types(context, + model.node_types, + context.presentation.get('service_template', 'node_types')) + model.group_types = Type(variant='group') + create_types(context, + model.group_types, + context.presentation.get('service_template', 'group_types')) + model.policy_types = Type(variant='policy') + create_types(context, + model.policy_types, + context.presentation.get('service_template', 'policy_types')) + model.relationship_types = Type(variant='relationship') + create_types(context, + model.relationship_types, + context.presentation.get('service_template', 'relationship_types')) + model.capability_types = Type(variant='capability') + create_types(context, + model.capability_types, + context.presentation.get('service_template', 'capability_types')) + model.interface_types = Type(variant='interface') + create_types(context, + model.interface_types, + context.presentation.get('service_template', 'interface_types')) + model.artifact_types = Type(variant='artifact') + create_types(context, + model.artifact_types, + context.presentation.get('service_template', 'artifact_types')) + + # Topology template + topology_template = context.presentation.get('service_template', 'topology_template') + if topology_template is not None: + model.inputs.update( + create_input_models_from_values(topology_template._get_input_values(context))) + model.outputs.update( + create_output_models_from_values(topology_template._get_output_values(context))) + + # Plugin specifications + policies = context.presentation.get('service_template', 'topology_template', 'policies') + if policies: + for policy in policies.itervalues(): + role = model.policy_types.get_descendant(policy.type).role + if role == 'plugin': + plugin_specification = create_plugin_specification_model(context, policy) + model.plugin_specifications[plugin_specification.name] = plugin_specification + elif role == 'workflow': + operation_template = create_workflow_operation_template_model(context, + model, policy) + model.workflow_templates[operation_template.name] = operation_template + + # Node templates + node_templates = context.presentation.get('service_template', 'topology_template', + 'node_templates') + if node_templates: + for node_template in node_templates.itervalues(): + node_template_model = create_node_template_model(context, model, node_template) + model.node_templates[node_template_model.name] = node_template_model + for node_template in node_templates.itervalues(): + fix_node_template_model(context, model, node_template) + + # Group templates + groups = context.presentation.get('service_template', 'topology_template', 'groups') + if groups: + for group in groups.itervalues(): + group_template_model = create_group_template_model(context, model, group) + model.group_templates[group_template_model.name] = group_template_model + + # Policy templates + policies = context.presentation.get('service_template', 'topology_template', 'policies') + if policies: + for policy in policies.itervalues(): + policy_template_model = create_policy_template_model(context, model, policy) + model.policy_templates[policy_template_model.name] = policy_template_model + + # Substitution template + substitution_mappings = context.presentation.get('service_template', 'topology_template', + 'substitution_mappings') + if substitution_mappings: + model.substitution_template = create_substitution_template_model(context, model, + substitution_mappings) + + return model + + +def create_metadata_models(context, service_template, metadata): + service_template.meta_data['template_name'] = Metadata(name='template_name', + value=metadata.template_name) + service_template.meta_data['template_author'] = Metadata(name='template_author', + value=metadata.template_author) + service_template.meta_data['template_version'] = Metadata(name='template_version', + value=metadata.template_version) + custom = metadata.custom + if custom: + for name, value in custom.iteritems(): + service_template.meta_data[name] = Metadata(name=name, + value=value) + + +def create_node_template_model(context, service_template, node_template): + node_type = node_template._get_type(context) + node_type = service_template.node_types.get_descendant(node_type._name) + model = NodeTemplate(name=node_template._name, type=node_type) + + if node_template.description: + model.description = node_template.description.value + + if node_template.directives: + model.directives = node_template.directives + + model.properties.update(create_property_models_from_values( + template_properties=node_template._get_property_values(context))) + model.attributes.update(create_attribute_models_from_values( + template_attributes=node_template._get_attribute_default_values(context))) + + create_interface_template_models(context, service_template, model.interface_templates, + node_template._get_interfaces(context)) + + artifacts = node_template._get_artifacts(context) + if artifacts: + for artifact_name, artifact in artifacts.iteritems(): + model.artifact_templates[artifact_name] = \ + create_artifact_template_model(context, service_template, artifact) + + capabilities = node_template._get_capabilities(context) + if capabilities: + for capability_name, capability in capabilities.iteritems(): + model.capability_templates[capability_name] = \ + create_capability_template_model(context, service_template, capability) + + if node_template.node_filter: + model.target_node_template_constraints = [] + create_node_filter_constraints(context, node_template.node_filter, + model.target_node_template_constraints) + + return model + + +def fix_node_template_model(context, service_template, node_template): + # Requirements have to be created after all node templates have been created, because + # requirements might reference another node template + model = service_template.node_templates[node_template._name] + requirements = node_template._get_requirements(context) + if requirements: + for _, requirement in requirements: + model.requirement_templates.append(create_requirement_template_model(context, + service_template, + requirement)) + + +def create_group_template_model(context, service_template, group): + group_type = group._get_type(context) + group_type = service_template.group_types.get_descendant(group_type._name) + model = GroupTemplate(name=group._name, + type=group_type) + + if group.description: + model.description = group.description.value + + model.properties.update(create_property_models_from_values(group._get_property_values(context))) + + create_interface_template_models(context, service_template, model.interface_templates, + group._get_interfaces(context)) + members = group.members + if members: + for member in members: + node_template = service_template.node_templates[member] + assert node_template + model.node_templates.append(node_template) + + return model + + +def create_policy_template_model(context, service_template, policy): + policy_type = policy._get_type(context) + policy_type = service_template.policy_types.get_descendant(policy_type._name) + model = PolicyTemplate(name=policy._name, + type=policy_type) + + if policy.description: + model.description = policy.description.value + + model.properties.update( + create_property_models_from_values(policy._get_property_values(context))) + + node_templates, groups = policy._get_targets(context) + if node_templates: + for target in node_templates: + node_template = service_template.node_templates[target._name] + assert node_template + model.node_templates.append(node_template) + if groups: + for target in groups: + group_template = service_template.group_templates[target._name] + assert group_template + model.group_templates.append(group_template) + + return model + + +def create_requirement_template_model(context, service_template, requirement): + model = {'name': requirement._name} + + node, node_variant = requirement._get_node(context) + if node is not None: + if node_variant == 'node_type': + node_type = service_template.node_types.get_descendant(node._name) + model['target_node_type'] = node_type + else: + node_template = service_template.node_templates[node._name] + model['target_node_template'] = node_template + + capability, capability_variant = requirement._get_capability(context) + if capability is not None: + if capability_variant == 'capability_type': + capability_type = \ + service_template.capability_types.get_descendant(capability._name) + model['target_capability_type'] = capability_type + else: + model['target_capability_name'] = capability._name + + model = RequirementTemplate(**model) + + if requirement.node_filter: + model.target_node_template_constraints = [] + create_node_filter_constraints(context, requirement.node_filter, + model.target_node_template_constraints) + + relationship = requirement.relationship + if relationship is not None: + model.relationship_template = \ + create_relationship_template_model(context, service_template, relationship) + model.relationship_template.name = requirement._name + + return model + + +def create_relationship_template_model(context, service_template, relationship): + relationship_type, relationship_type_variant = relationship._get_type(context) + if relationship_type_variant == 'relationship_type': + relationship_type = service_template.relationship_types.get_descendant( + relationship_type._name) + model = RelationshipTemplate(type=relationship_type) + else: + relationship_template = relationship_type + relationship_type = relationship_template._get_type(context) + relationship_type = service_template.relationship_types.get_descendant( + relationship_type._name) + model = RelationshipTemplate(type=relationship_type) + if relationship_template.description: + model.description = relationship_template.description.value + + create_parameter_models_from_assignments(model.properties, + relationship.properties, + model_cls=Property) + create_interface_template_models(context, service_template, model.interface_templates, + relationship.interfaces) + + return model + + +def create_capability_template_model(context, service_template, capability): + capability_type = capability._get_type(context) + capability_type = service_template.capability_types.get_descendant(capability_type._name) + model = CapabilityTemplate(name=capability._name, + type=capability_type) + + capability_definition = capability._get_definition(context) + if capability_definition.description: + model.description = capability_definition.description.value + occurrences = capability_definition.occurrences + if occurrences is not None: + model.min_occurrences = occurrences.value[0] + if occurrences.value[1] != 'UNBOUNDED': + model.max_occurrences = occurrences.value[1] + + valid_source_types = capability_definition.valid_source_types + if valid_source_types: + for valid_source_type in valid_source_types: + # TODO: handle shortcut type names + node_type = service_template.node_types.get_descendant(valid_source_type) + model.valid_source_node_types.append(node_type) + + create_parameter_models_from_assignments(model.properties, + capability.properties, + model_cls=Property) + + return model + + +def create_interface_template_model(context, service_template, interface): + interface_type = interface._get_type(context) + interface_type = service_template.interface_types.get_descendant(interface_type._name) + model = InterfaceTemplate(name=interface._name, type=interface_type) + + if interface_type.description: + model.description = interface_type.description + + create_parameter_models_from_assignments(model.inputs, interface.inputs, model_cls=Input) + + operations = interface.operations + if operations: + for operation_name, operation in operations.iteritems(): + model.operation_templates[operation_name] = \ + create_operation_template_model(context, service_template, operation) + + return model if model.operation_templates else None + + +def create_operation_template_model(context, service_template, operation): + model = OperationTemplate(name=operation._name) + + if operation.description: + model.description = operation.description.value + + implementation = operation.implementation + if implementation is not None: + primary = implementation.primary + extract_implementation_primary(context, service_template, operation, model, primary) + relationship_edge = operation._get_extensions(context).get('relationship_edge') + if relationship_edge is not None: + if relationship_edge == 'source': + model.relationship_edge = False + elif relationship_edge == 'target': + model.relationship_edge = True + + dependencies = implementation.dependencies + configuration = OrderedDict() + if dependencies: + for dependency in dependencies: + key, value = split_prefix(dependency) + if key is not None: + # Special ARIA prefix: signifies configuration parameters + + # Parse as YAML + try: + value = yaml.load(value) + except yaml.parser.MarkedYAMLError as e: + context.validation.report( + 'YAML parser {0} in operation configuration: {1}' + .format(e.problem, value), + locator=implementation._locator, + level=Issue.FIELD) + continue + + # Coerce to intrinsic functions, if there are any + value = coerce_parameter_value(context, implementation, None, value).value + + # Support dot-notation nesting + set_nested(configuration, key.split('.'), value) + else: + if model.dependencies is None: + model.dependencies = [] + model.dependencies.append(dependency) + + # Convert configuration to Configuration models + for key, value in configuration.iteritems(): + model.configurations[key] = Configuration.wrap(key, value, + description='Operation configuration.') + + create_parameter_models_from_assignments(model.inputs, operation.inputs, model_cls=Input) + return model + + +def create_artifact_template_model(context, service_template, artifact): + artifact_type = artifact._get_type(context) + artifact_type = service_template.artifact_types.get_descendant(artifact_type._name) + model = ArtifactTemplate(name=artifact._name, + type=artifact_type, + source_path=artifact.file) + + if artifact.description: + model.description = artifact.description.value + + model.target_path = artifact.deploy_path + + repository = artifact._get_repository(context) + if repository is not None: + model.repository_url = repository.url + credential = repository._get_credential(context) + if credential: + model.repository_credential = {} + for k, v in credential.iteritems(): + model.repository_credential[k] = v + + model.properties.update( + create_property_models_from_values(artifact._get_property_values(context))) + + return model + + +def create_substitution_template_model(context, service_template, substitution_mappings): + node_type = service_template.node_types.get_descendant(substitution_mappings.node_type) + model = SubstitutionTemplate(node_type=node_type) + + capabilities = substitution_mappings.capabilities + if capabilities: + for mapped_capability_name, capability in capabilities.iteritems(): + name = 'capability.' + mapped_capability_name + node_template_model = service_template.node_templates[capability.node_template] + capability_template_model = \ + node_template_model.capability_templates[capability.capability] + model.mappings[name] = \ + SubstitutionTemplateMapping(name=name, + capability_template=capability_template_model) + + requirements = substitution_mappings.requirements + if requirements: + for mapped_requirement_name, requirement in requirements.iteritems(): + name = 'requirement.' + mapped_requirement_name + node_template_model = service_template.node_templates[requirement.node_template] + requirement_template_model = None + for a_model in node_template_model.requirement_templates: + if a_model.name == requirement.requirement: + requirement_template_model = a_model + break + model.mappings[name] = \ + SubstitutionTemplateMapping(name=name, + requirement_template=requirement_template_model) + + return model + + +def create_plugin_specification_model(context, policy): + properties = policy.properties + + def get(name, default=None): + prop = properties.get(name) + return prop.value if prop is not None else default + + model = PluginSpecification(name=policy._name, + version=get('version'), + enabled=get('enabled', True)) + + return model + + +def create_workflow_operation_template_model(context, service_template, policy): + model = OperationTemplate(name=policy._name) + # since we use backpopulates, these fields are populated upon commit, we get a weird(temporary) + # behavior where in previous code service_template.workflow_templates is a dict which has None + # as key for the value of model. + service_template.workflow_templates[model.name] = model + + if policy.description: + model.description = policy.description.value + + properties = policy._get_property_values(context) + for prop_name, prop in properties.iteritems(): + if prop_name == 'implementation': + model.function = prop.value + else: + input_model = create_parameter_model_from_value(prop, prop_name, model_cls=Input) + input_model.required = prop.required + model.inputs[prop_name] = input_model + + used_reserved_names = WORKFLOW_DECORATOR_RESERVED_ARGUMENTS.intersection(model.inputs.keys()) + if used_reserved_names: + context.validation.report('using reserved arguments in workflow policy "{0}": {1}' + .format( + policy._name, + string_list_as_string(used_reserved_names)), + locator=policy._locator, + level=Issue.EXTERNAL) + return model + + +# +# Utils +# + +def create_types(context, root, types): + if types is None: + return + + def added_all(): + for name in types: + if root.get_descendant(name) is None: + return False + return True + + while not added_all(): + for name, the_type in types.iteritems(): + if root.get_descendant(name) is None: + parent_type = the_type._get_parent(context) + model = Type(name=the_type._name, + role=the_type._get_extension('role')) + if the_type.description: + model.description = the_type.description.value + if parent_type is None: + model.parent = root + model.variant = root.variant + root.children.append(model) + else: + container = root.get_descendant(parent_type._name) + if container is not None: + model.parent = container + model.variant = container.variant + container.children.append(model) + + +def create_input_models_from_values(template_inputs): + model_inputs = {} + if template_inputs: + for template_input_name, template_input in template_inputs.iteritems(): + model_input = create_parameter_model_from_value(template_input, template_input_name, + model_cls=Input) + model_input.required = template_input.required + model_inputs[model_input.name] = model_input + return model_inputs + +def create_output_models_from_values(template_outputs): + model_outputs = {} + for template_output_name, template_output in template_outputs.iteritems(): + model_outputs[template_output_name] = \ + create_parameter_model_from_value(template_output, + template_output_name, + model_cls=Output) + return model_outputs + + +def create_property_models_from_values(template_properties): + model_properties = {} + for template_property_name, template_property in template_properties.iteritems(): + model_properties[template_property_name] = \ + create_parameter_model_from_value(template_property, + template_property_name, + model_cls=Property) + return model_properties + +def create_attribute_models_from_values(template_attributes): + model_attributes = {} + for template_attribute_name, template_attribute in template_attributes.iteritems(): + model_attributes[template_attribute_name] = \ + create_parameter_model_from_value(template_attribute, + template_attribute_name, + model_cls=Attribute) + return model_attributes + + +def create_parameter_model_from_value(template_parameter, template_parameter_name, model_cls): + return model_cls(name=template_parameter_name, + type_name=template_parameter.type, + value=template_parameter.value, + description=template_parameter.description) + + +def create_parameter_models_from_assignments(properties, source_properties, model_cls): + if source_properties: + for property_name, prop in source_properties.iteritems(): + properties[property_name] = model_cls(name=property_name, # pylint: disable=unexpected-keyword-arg + type_name=prop.value.type, + value=prop.value.value, + description=prop.value.description) + + +def create_interface_template_models(context, service_template, interfaces, source_interfaces): + if source_interfaces: + for interface_name, interface in source_interfaces.iteritems(): + interface = create_interface_template_model(context, service_template, interface) + if interface is not None: + interfaces[interface_name] = interface + + +def create_node_filter_constraints(context, node_filter, target_node_template_constraints): + properties = node_filter.properties + if properties is not None: + for property_name, constraint_clause in properties: + constraint = create_constraint(context, node_filter, constraint_clause, property_name, + None) + target_node_template_constraints.append(constraint) + + capabilities = node_filter.capabilities + if capabilities is not None: + for capability_name, capability in capabilities: + properties = capability.properties + if properties is not None: + for property_name, constraint_clause in properties: + constraint = create_constraint(context, node_filter, constraint_clause, + property_name, capability_name) + target_node_template_constraints.append(constraint) + + +def create_constraint(context, node_filter, constraint_clause, property_name, capability_name): # pylint: disable=too-many-return-statements + constraint_key = constraint_clause._raw.keys()[0] + + the_type = constraint_clause._get_type(context) + + def coerce_constraint(constraint): + if the_type is not None: + return coerce_value(context, node_filter, the_type, None, None, constraint, + constraint_key) + else: + return constraint + + def coerce_constraints(constraints): + if the_type is not None: + return tuple(coerce_constraint(constraint) for constraint in constraints) + else: + return constraints + + if constraint_key == 'equal': + return Equal(property_name, capability_name, + coerce_constraint(constraint_clause.equal)) + elif constraint_key == 'greater_than': + return GreaterThan(property_name, capability_name, + coerce_constraint(constraint_clause.greater_than)) + elif constraint_key == 'greater_or_equal': + return GreaterOrEqual(property_name, capability_name, + coerce_constraint(constraint_clause.greater_or_equal)) + elif constraint_key == 'less_than': + return LessThan(property_name, capability_name, + coerce_constraint(constraint_clause.less_than)) + elif constraint_key == 'less_or_equal': + return LessOrEqual(property_name, capability_name, + coerce_constraint(constraint_clause.less_or_equal)) + elif constraint_key == 'in_range': + return InRange(property_name, capability_name, + coerce_constraints(constraint_clause.in_range)) + elif constraint_key == 'valid_values': + return ValidValues(property_name, capability_name, + coerce_constraints(constraint_clause.valid_values)) + elif constraint_key == 'length': + return Length(property_name, capability_name, + coerce_constraint(constraint_clause.length)) + elif constraint_key == 'min_length': + return MinLength(property_name, capability_name, + coerce_constraint(constraint_clause.min_length)) + elif constraint_key == 'max_length': + return MaxLength(property_name, capability_name, + coerce_constraint(constraint_clause.max_length)) + elif constraint_key == 'pattern': + return Pattern(property_name, capability_name, + coerce_constraint(constraint_clause.pattern)) + else: + raise ValueError('malformed node_filter: {0}'.format(constraint_key)) + + +def split_prefix(string): + """ + Splits the prefix on the first non-escaped ">". + """ + + split = IMPLEMENTATION_PREFIX_REGEX.split(string, 1) + if len(split) < 2: + return None, None + return split[0].strip(), split[1].strip() + + +def set_nested(the_dict, keys, value): + """ + If the ``keys`` list has just one item, puts the value in the the dict. If there are more items, + puts the value in a sub-dict, creating sub-dicts as necessary for each key. + + For example, if ``the_dict`` is an empty dict, keys is ``['first', 'second', 'third']`` and + value is ``'value'``, then the_dict will be: ``{'first':{'second':{'third':'value'}}}``. + + :param the_dict: Dict to change + :type the_dict: {} + :param keys: Keys + :type keys: [basestring] + :param value: Value + """ + key = keys.pop(0) + if len(keys) == 0: + the_dict[key] = value + else: + if key not in the_dict: + the_dict[key] = StrictDict(key_class=basestring) + set_nested(the_dict[key], keys, value) + + +def extract_implementation_primary(context, service_template, presentation, model, primary): + prefix, postfix = split_prefix(primary) + if prefix: + # Special ARIA prefix + model.plugin_specification = service_template.plugin_specifications.get(prefix) + model.function = postfix + if model.plugin_specification is None: + context.validation.report( + 'no policy for plugin "{0}" specified in operation implementation: {1}' + .format(prefix, primary), + locator=presentation._get_child_locator('properties', 'implementation'), + level=Issue.BETWEEN_TYPES) + else: + # Standard TOSCA artifact with default plugin + model.implementation = primary diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py new file mode 100644 index 0000000..b45615a --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py @@ -0,0 +1,44 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import OrderedDict + + +# +# NodeType, NodeTemplate +# + +def get_inherited_artifact_definitions(context, presentation, for_presentation=None): + if for_presentation is None: + for_presentation = presentation + + if hasattr(presentation, '_get_type'): + # In NodeTemplate + parent = presentation._get_type(context) + else: + # In NodeType + parent = presentation._get_parent(context) + + # Get artifact definitions from parent + artifacts = get_inherited_artifact_definitions(context, parent, for_presentation) \ + if parent is not None else OrderedDict() + + # Add/override our artifact definitions + our_artifacts = presentation.artifacts + if our_artifacts: + for artifact_name, artifact in our_artifacts.iteritems(): + artifacts[artifact_name] = artifact._clone(for_presentation) + + return artifacts diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py new file mode 100644 index 0000000..1b95bec --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py @@ -0,0 +1,220 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import deepcopy_with_locators, OrderedDict +from aria.parser.validation import Issue + +from .parameters import (convert_parameter_definitions_to_values, merge_raw_parameter_definitions, + get_assigned_and_defined_parameter_values) + + +# +# CapabilityType +# + +def get_inherited_valid_source_types(context, presentation): + """ + If we haven't set the ``valid_source_types`` fields, uses that value from our parent, if we have + one (recursively). + """ + + valid_source_types = presentation.valid_source_types + + if valid_source_types is None: + parent = presentation._get_parent(context) + valid_source_types = get_inherited_valid_source_types(context, parent) \ + if parent is not None else None + + return valid_source_types + + +# +# NodeType +# + +def get_inherited_capability_definitions(context, presentation, for_presentation=None): + """ + Returns our capability capability definitions added on top of those of our parent, if we have + one (recursively). + + Allows overriding all aspects of parent capability properties except data type. + """ + + if for_presentation is None: + for_presentation = presentation + + # Get capability definitions from parent + parent = presentation._get_parent(context) + capability_definitions = get_inherited_capability_definitions( + context, parent, for_presentation) if parent is not None else OrderedDict() + + # Add/merge our capability definitions + our_capability_definitions = presentation.capabilities + if our_capability_definitions: + for capability_name, our_capability_definition in our_capability_definitions.iteritems(): + if capability_name in capability_definitions: + capability_definition = capability_definitions[capability_name] + + # Check if we changed the type + type1 = capability_definition._get_type(context) + type2 = our_capability_definition._get_type(context) + + if not type1._is_descendant(context, type2): + context.validation.report( + 'capability definition type "{0}" is not a descendant of overridden ' + 'capability definition type "{1}"' \ + .format(type1._name, type2._name), + locator=our_capability_definition._locator, level=Issue.BETWEEN_TYPES) + + merge_capability_definition(context, presentation, capability_definition, + our_capability_definition) + else: + capability_definition = our_capability_definition._clone(for_presentation) + if isinstance(capability_definition._raw, basestring): + # Make sure we have a dict + the_type = capability_definition._raw + capability_definition._raw = OrderedDict() + capability_definition._raw['type'] = the_type + capability_definitions[capability_name] = capability_definition + + merge_capability_definition_from_type(context, presentation, capability_definition) + + for capability_definition in capability_definitions.itervalues(): + capability_definition._reset_method_cache() + + return capability_definitions + + +# +# NodeTemplate +# + +def get_template_capabilities(context, presentation): + """ + Returns the node type's capabilities with our assignments to properties and attributes merged + in. + + Capability properties' default values, if available, will be used if we did not assign them. + + Makes sure that required properties indeed end up with a value. + """ + + capability_assignments = OrderedDict() + + the_type = presentation._get_type(context) # NodeType + capability_definitions = the_type._get_capabilities(context) if the_type is not None else None + + # Copy over capability definitions from the type (will initialize properties with default + # values) + if capability_definitions: + for capability_name, capability_definition in capability_definitions.iteritems(): + capability_assignments[capability_name] = \ + convert_capability_from_definition_to_assignment(context, capability_definition, + presentation) + + # Fill in our capability assignments + our_capability_assignments = presentation.capabilities + if our_capability_assignments: + for capability_name, our_capability_assignment in our_capability_assignments.iteritems(): + if capability_name in capability_assignments: + capability_assignment = capability_assignments[capability_name] + + # Assign properties + values = get_assigned_and_defined_parameter_values(context, + our_capability_assignment, + 'property') + + if values: + capability_assignment._raw['properties'] = values + capability_assignment._reset_method_cache() + else: + context.validation.report( + 'capability "{0}" not declared at node type "{1}" in "{2}"' + .format(capability_name, presentation.type, presentation._fullname), + locator=our_capability_assignment._locator, level=Issue.BETWEEN_TYPES) + + return capability_assignments + + +# +# Utils +# + +def convert_capability_from_definition_to_assignment(context, presentation, container): + from ..assignments import CapabilityAssignment + + raw = OrderedDict() + + properties = presentation.properties + if properties is not None: + raw['properties'] = convert_parameter_definitions_to_values(context, properties) + + # TODO attributes + + return CapabilityAssignment(name=presentation._name, raw=raw, container=container) + + +def merge_capability_definition(context, presentation, capability_definition, + from_capability_definition): + raw_properties = OrderedDict() + + capability_definition._raw['type'] = from_capability_definition.type + + # Merge properties from type + from_property_defintions = from_capability_definition.properties + merge_raw_parameter_definitions(context, presentation, raw_properties, from_property_defintions, + 'properties') + + # Merge our properties + merge_raw_parameter_definitions(context, presentation, raw_properties, + capability_definition.properties, 'properties') + + if raw_properties: + capability_definition._raw['properties'] = raw_properties + capability_definition._reset_method_cache() + + # Merge occurrences + occurrences = from_capability_definition._raw.get('occurrences') + if (occurrences is not None) and (capability_definition._raw.get('occurrences') is None): + capability_definition._raw['occurrences'] = \ + deepcopy_with_locators(occurrences) + + +def merge_capability_definition_from_type(context, presentation, capability_definition): + """ + Merge ``properties`` and ``valid_source_types`` from the node type's capability definition + over those taken from the parent node type. + """ + raw_properties = OrderedDict() + + # Merge properties from parent + the_type = capability_definition._get_type(context) + type_property_defintions = the_type._get_properties(context) + merge_raw_parameter_definitions(context, presentation, raw_properties, type_property_defintions, + 'properties') + + # Merge our properties (might override definitions in parent) + merge_raw_parameter_definitions(context, presentation, raw_properties, + capability_definition.properties, 'properties') + + if raw_properties: + capability_definition._raw['properties'] = raw_properties + + # Override valid_source_types + if capability_definition._raw.get('valid_source_types') is None: + valid_source_types = the_type._get_valid_source_types(context) + if valid_source_types is not None: + capability_definition._raw['valid_source_types'] = \ + deepcopy_with_locators(valid_source_types) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py new file mode 100644 index 0000000..9a30cc1 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py @@ -0,0 +1,144 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re + +from aria.modeling.constraints import NodeTemplateConstraint +from aria.modeling.utils import NodeTemplateContainerHolder +from aria.modeling.functions import evaluate +from aria.parser import implements_specification + + +@implements_specification('3.5.2-2', 'tosca-simple-1.0') +class EvaluatingNodeTemplateConstraint(NodeTemplateConstraint): + """ + A version of :class:`NodeTemplateConstraint` with boilerplate initialization for TOSCA + constraints. + """ + + def __init__(self, property_name, capability_name, constraint, as_list=False): + self.property_name = property_name + self.capability_name = capability_name + self.constraint = constraint + self.as_list = as_list + + def matches(self, source_node_template, target_node_template): + # TOSCA node template constraints can refer to either capability properties or node + # template properties + if self.capability_name is not None: + # Capability property + capability = target_node_template.capability_templates.get(self.capability_name) + value = capability.properties.get(self.property_name) \ + if capability is not None else None # Parameter + else: + # Node template property + value = target_node_template.properties.get(self.property_name) # Parameter + + value = value.value if value is not None else None + + container_holder = NodeTemplateContainerHolder(source_node_template) + + if self.as_list: + constraints = [] + for constraint in self.constraint: + evaluation = evaluate(constraint, container_holder) + if evaluation is not None: + constraints.append(evaluation.value) + else: + constraints.append(constraint) + constraint = constraints + else: + evaluation = evaluate(self.constraint, container_holder) + if evaluation is not None: + constraint = evaluation.value + else: + constraint = self.constraint + + return self.matches_evaluated(value, constraint) + + def matches_evaluated(self, value, constraint): + raise NotImplementedError + + +class Equal(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return value == constraint + + +class GreaterThan(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return value > constraint + + +class GreaterOrEqual(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return value >= constraint + + +class LessThan(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return value < constraint + + +class LessOrEqual(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return value <= constraint + + +class InRange(EvaluatingNodeTemplateConstraint): + def __init__(self, property_name, capability_name, constraint): + super(InRange, self).__init__(property_name, capability_name, constraint, as_list=True) + + def matches_evaluated(self, value, constraints): + lower, upper = constraints + if value < lower: + return False + if (upper != 'UNBOUNDED') and (value > upper): + return False + return True + + +class ValidValues(EvaluatingNodeTemplateConstraint): + def __init__(self, property_name, capability_name, constraint): + super(ValidValues, self).__init__(property_name, capability_name, constraint, as_list=True) + + def matches_evaluated(self, value, constraints): + return value in constraints + + +class Length(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return len(value) == constraint + + +class MinLength(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return len(value) >= constraint + + +class MaxLength(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + return len(value) <= constraint + + +class Pattern(EvaluatingNodeTemplateConstraint): + def matches_evaluated(self, value, constraint): + # From TOSCA 1.0 3.5.2.1: + # + # "Note: Future drafts of this specification will detail the use of regular expressions and + # reference an appropriate standardized grammar." + # + # So we will just use Python's. + return re.match(constraint, unicode(value)) is not None diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py new file mode 100644 index 0000000..bd9037f --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# NodeTemplate, RelationshipTemplate +# + +def get_default_raw_from_copy(presentation, field_name): + """ + Used for the ``_get_default_raw`` field hook. + """ + + copy = presentation._raw.get('copy') + if copy is not None: + templates = getattr(presentation._container, field_name) + if templates is not None: + template = templates.get(copy) + if template is not None: + return template._raw + return None diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py new file mode 100644 index 0000000..13ce9a3 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py @@ -0,0 +1,514 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re + +from aria.utils.collections import OrderedDict +from aria.utils.formatting import safe_repr +from aria.utils.type import full_type_name +from aria.utils.imports import import_fullname +from aria.parser import implements_specification +from aria.parser.presentation import (get_locator, validate_primitive) +from aria.parser.validation import Issue + +from .functions import get_function +from ..presentation.types import get_type_by_name + + +# +# DataType +# + +def get_inherited_constraints(context, presentation): + """ + If we don't have constraints, will return our parent's constraints (if we have one), + recursively. + + Implication: if we define even one constraint, the parent's constraints will not be inherited. + """ + + constraints = presentation.constraints + + if constraints is None: + # If we don't have any, use our parent's + parent = presentation._get_parent(context) + parent_constraints = get_inherited_constraints(context, parent) \ + if parent is not None else None + if parent_constraints is not None: + constraints = parent_constraints + + return constraints + + +def coerce_data_type_value(context, presentation, data_type, entry_schema, constraints, value, # pylint: disable=unused-argument + aspect): + """ + Handles the ``_coerce_data()`` hook for complex data types. + + There are two kinds of handling: + + 1. If we have a primitive type as our great ancestor, then we do primitive type coersion, and + just check for constraints. + + 2. Otherwise, for normal complex data types we return the assigned property values while making + sure they are defined in our type. The property definition's default value, if available, + will be used if we did not assign it. We also make sure that required definitions indeed end + up with a value. + """ + + primitive_type = data_type._get_primitive_ancestor(context) + if primitive_type is not None: + # Must be coercible to primitive ancestor + value = coerce_to_primitive(context, presentation, primitive_type, constraints, value, + aspect) + else: + definitions = data_type._get_properties(context) + if isinstance(value, dict): + temp = OrderedDict() + + # Fill in our values, but make sure they are defined + for name, v in value.iteritems(): + if name in definitions: + definition = definitions[name] + definition_type = definition._get_type(context) + definition_entry_schema = definition.entry_schema + definition_constraints = definition._get_constraints(context) + temp[name] = coerce_value(context, presentation, definition_type, + definition_entry_schema, definition_constraints, v, + aspect) + else: + context.validation.report( + 'assignment to undefined property "%s" in type "%s" in "%s"' + % (name, data_type._fullname, presentation._fullname), + locator=get_locator(v, value, presentation), level=Issue.BETWEEN_TYPES) + + # Fill in defaults from the definitions, and check if required definitions have not been + # assigned + for name, definition in definitions.iteritems(): + if (temp.get(name) is None) and hasattr(definition, 'default') \ + and (definition.default is not None): + definition_type = definition._get_type(context) + definition_entry_schema = definition.entry_schema + definition_constraints = definition._get_constraints(context) + temp[name] = coerce_value(context, presentation, definition_type, + definition_entry_schema, definition_constraints, + definition.default, 'default') + + if getattr(definition, 'required', False) and (temp.get(name) is None): + context.validation.report( + 'required property "%s" in type "%s" is not assigned a value in "%s"' + % (name, data_type._fullname, presentation._fullname), + locator=presentation._get_child_locator('definitions'), + level=Issue.BETWEEN_TYPES) + + value = temp + elif value is not None: + context.validation.report('value of type "%s" is not a dict in "%s"' + % (data_type._fullname, presentation._fullname), + locator=get_locator(value, presentation), + level=Issue.BETWEEN_TYPES) + value = None + + return value + + +def validate_data_type_name(context, presentation): + """ + Makes sure the complex data type's name is not that of a built-in type. + """ + + name = presentation._name + if get_primitive_data_type(name) is not None: + context.validation.report('data type name is that of a built-in type: %s' + % safe_repr(name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + +# +# PropertyDefinition, AttributeDefinition, EntrySchema, DataType +# + +def get_data_type(context, presentation, field_name, allow_none=False): + """ + Returns the type, whether it's a complex data type (a DataType instance) or a primitive (a + Python primitive type class). + + If the type is not specified, defaults to :class:`str`, per note in section 3.2.1.1 of the + `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #_Toc379455072>`__ + """ + + type_name = getattr(presentation, field_name) + + if type_name is None: + if allow_none: + return None + else: + return str + + # Avoid circular definitions + container_data_type = get_container_data_type(presentation) + if (container_data_type is not None) and (container_data_type._name == type_name): + return None + + # Try complex data type + data_type = get_type_by_name(context, type_name, 'data_types') + if data_type is not None: + return data_type + + # Try primitive data type + return get_primitive_data_type(type_name) + + +# +# PropertyDefinition, EntrySchema +# + +def get_property_constraints(context, presentation): + """ + If we don't have constraints, will return our type's constraints (if we have one), recursively. + + Implication: if we define even one constraint, the type's constraints will not be inherited. + """ + + constraints = presentation.constraints + + if constraints is None: + # If we don't have any, use our type's + the_type = presentation._get_type(context) + type_constraints = the_type._get_constraints(context) \ + if hasattr(the_type, '_get_constraints') else None + if type_constraints is not None: + constraints = type_constraints + + return constraints + + +# +# ConstraintClause +# + +def apply_constraint_to_value(context, presentation, constraint_clause, value): # pylint: disable=too-many-statements,too-many-return-statements,too-many-branches + """ + Returns false if the value does not conform to the constraint. + """ + + constraint_key = constraint_clause._raw.keys()[0] + the_type = constraint_clause._get_type(context) + # PropertyAssignment does not have this: + entry_schema = getattr(presentation, 'entry_schema', None) + + def coerce_constraint(constraint): + return coerce_value(context, presentation, the_type, entry_schema, None, constraint, + constraint_key) + + def report(message, constraint): + context.validation.report('value %s %s per constraint in "%s": %s' + % (message, safe_repr(constraint), + presentation._name or presentation._container._name, + safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_FIELDS) + + if constraint_key == 'equal': + constraint = coerce_constraint(constraint_clause.equal) + if value != constraint: + report('is not equal to', constraint) + return False + + elif constraint_key == 'greater_than': + constraint = coerce_constraint(constraint_clause.greater_than) + if value <= constraint: + report('is not greater than', constraint) + return False + + elif constraint_key == 'greater_or_equal': + constraint = coerce_constraint(constraint_clause.greater_or_equal) + if value < constraint: + report('is not greater than or equal to', constraint) + return False + + elif constraint_key == 'less_than': + constraint = coerce_constraint(constraint_clause.less_than) + if value >= constraint: + report('is not less than', constraint) + return False + + elif constraint_key == 'less_or_equal': + constraint = coerce_constraint(constraint_clause.less_or_equal) + if value > constraint: + report('is not less than or equal to', constraint) + return False + + elif constraint_key == 'in_range': + lower, upper = constraint_clause.in_range + lower, upper = coerce_constraint(lower), coerce_constraint(upper) + if value < lower: + report('is not greater than or equal to lower bound', lower) + return False + if (upper != 'UNBOUNDED') and (value > upper): + report('is not lesser than or equal to upper bound', upper) + return False + + elif constraint_key == 'valid_values': + constraint = tuple(coerce_constraint(v) for v in constraint_clause.valid_values) + if value not in constraint: + report('is not one of', constraint) + return False + + elif constraint_key == 'length': + constraint = constraint_clause.length + try: + if len(value) != constraint: + report('is not of length', constraint) + return False + except TypeError: + pass # should be validated elsewhere + + elif constraint_key == 'min_length': + constraint = constraint_clause.min_length + try: + if len(value) < constraint: + report('has a length lesser than', constraint) + return False + except TypeError: + pass # should be validated elsewhere + + elif constraint_key == 'max_length': + constraint = constraint_clause.max_length + try: + if len(value) > constraint: + report('has a length greater than', constraint) + return False + except TypeError: + pass # should be validated elsewhere + + elif constraint_key == 'pattern': + constraint = constraint_clause.pattern + try: + # From TOSCA 1.0 3.5.2.1: + # + # "Note: Future drafts of this specification will detail the use of regular expressions + # and reference an appropriate standardized grammar." + # + # So we will just use Python's. + if re.match(constraint, str(value)) is None: + report('does not match regular expression', constraint) + return False + except re.error: + pass # should be validated elsewhere + + return True + + +# +# Repository +# + +def get_data_type_value(context, presentation, field_name, type_name): + the_type = get_type_by_name(context, type_name, 'data_types') + if the_type is not None: + value = getattr(presentation, field_name) + if value is not None: + return coerce_data_type_value(context, presentation, the_type, None, None, value, None) + else: + context.validation.report('field "%s" in "%s" refers to unknown data type "%s"' + % (field_name, presentation._fullname, type_name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + return None + + +# +# Utils +# + +PRIMITIVE_DATA_TYPES = { + # YAML 1.2: + 'tag:yaml.org,2002:str': unicode, + 'tag:yaml.org,2002:integer': int, + 'tag:yaml.org,2002:float': float, + 'tag:yaml.org,2002:bool': bool, + 'tag:yaml.org,2002:null': None.__class__, + + # TOSCA aliases: + 'string': unicode, + 'integer': int, + 'float': float, + 'boolean': bool, + 'null': None.__class__} + + +@implements_specification('3.2.1-3', 'tosca-simple-1.0') +def get_primitive_data_type(type_name): + """ + Many of the types we use in this profile are built-in types from the YAML 1.2 specification + (i.e., those identified by the "tag:yaml.org,2002" version tag) [YAML-1.2]. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #_Toc373867862>`__ + """ + + return PRIMITIVE_DATA_TYPES.get(type_name) + + +def get_data_type_name(the_type): + """ + Returns the name of the type, whether it's a DataType, a primitive type, or another class. + """ + + return the_type._name if hasattr(the_type, '_name') else full_type_name(the_type) + + +def coerce_value(context, presentation, the_type, entry_schema, constraints, value, aspect=None): # pylint: disable=too-many-return-statements + """ + Returns the value after it's coerced to its type, reporting validation errors if it cannot be + coerced. + + Supports both complex data types and primitives. + + Data types can use the ``coerce_value`` extension to hook their own specialized function. + If the extension is present, we will delegate to that hook. + """ + + # TODO: should support models as well as presentations + + is_function, func = get_function(context, presentation, value) + if is_function: + return func + + if the_type is None: + return value + + if the_type == None.__class__: + if value is not None: + context.validation.report('field "%s" is of type "null" but has a non-null value: %s' + % (presentation._name, safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_FIELDS) + return None + + # Delegate to 'coerce_value' extension + if hasattr(the_type, '_get_extension'): + coerce_value_fn_name = the_type._get_extension('coerce_value') + if coerce_value_fn_name is not None: + if value is None: + return None + coerce_value_fn = import_fullname(coerce_value_fn_name) + return coerce_value_fn(context, presentation, the_type, entry_schema, constraints, + value, aspect) + + if hasattr(the_type, '_coerce_value'): + # Delegate to '_coerce_value' (likely a DataType instance) + return the_type._coerce_value(context, presentation, entry_schema, constraints, value, + aspect) + + # Coerce to primitive type + return coerce_to_primitive(context, presentation, the_type, constraints, value, aspect) + + +def coerce_to_primitive(context, presentation, primitive_type, constraints, value, aspect=None): + """ + Returns the value after it's coerced to a primitive type, translating exceptions to validation + errors if it cannot be coerced. + """ + + if value is None: + return None + + try: + # Coerce + value = validate_primitive(value, primitive_type, + context.validation.allow_primitive_coersion) + + # Check constraints + apply_constraints_to_value(context, presentation, constraints, value) + except (ValueError, TypeError) as e: + report_issue_for_bad_format(context, presentation, primitive_type, value, aspect, e) + value = None + + return value + + +def coerce_to_data_type_class(context, presentation, cls, entry_schema, constraints, value, + aspect=None): + """ + Returns the value after it's coerced to a data type class, reporting validation errors if it + cannot be coerced. Constraints will be applied after coersion. + + Will either call a ``_create`` static function in the class, or instantiate it using a + constructor if ``_create`` is not available. + + This will usually be called by a ``coerce_value`` extension hook in a :class:`DataType`. + """ + + try: + if hasattr(cls, '_create'): + # Instantiate using creator function + value = cls._create(context, presentation, entry_schema, constraints, value, aspect) + else: + # Normal instantiation + value = cls(entry_schema, constraints, value, aspect) + except ValueError as e: + report_issue_for_bad_format(context, presentation, cls, value, aspect, e) + value = None + + # Check constraints + value = apply_constraints_to_value(context, presentation, constraints, value) + + return value + + +def apply_constraints_to_value(context, presentation, constraints, value): + """ + Applies all constraints to the value. If the value conforms, returns the value. If it does not + conform, returns None. + """ + + if (value is not None) and (constraints is not None): + valid = True + for constraint in constraints: + if not constraint._apply_to_value(context, presentation, value): + valid = False + if not valid: + value = None + return value + + +def get_container_data_type(presentation): + if presentation is None: + return None + if type(presentation).__name__ == 'DataType': + return presentation + return get_container_data_type(presentation._container) + + +def report_issue_for_bad_format(context, presentation, the_type, value, aspect, e): + if aspect == 'default': + aspect = '"default" value' + elif aspect is not None: + aspect = '"%s" aspect' % aspect + + if aspect is not None: + context.validation.report('%s for field "%s" is not a valid "%s": %s' + % (aspect, presentation._name or presentation._container._name, + get_data_type_name(the_type), safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_FIELDS, + exception=e) + else: + context.validation.report('field "%s" is not a valid "%s": %s' + % (presentation._name or presentation._container._name, + get_data_type_name(the_type), safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_FIELDS, + exception=e) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py new file mode 100644 index 0000000..ecbfde9 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py @@ -0,0 +1,681 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from StringIO import StringIO # Note: cStringIO does not support Unicode +import re + +from aria.utils.collections import FrozenList +from aria.utils.formatting import (as_raw, safe_repr) +from aria.utils.type import full_type_name +from aria.parser import implements_specification +from aria.parser.exceptions import InvalidValueError +from aria.parser.validation import Issue +from aria.modeling.exceptions import CannotEvaluateFunctionException +from aria.modeling.models import (Node, NodeTemplate, Relationship, RelationshipTemplate) +from aria.modeling.functions import (Function, Evaluation) + + +# +# Intrinsic +# + +@implements_specification('4.3.1', 'tosca-simple-1.0') +class Concat(Function): + """ + The ``concat`` function is used to concatenate two or more string values within a TOSCA + service template. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + if not isinstance(argument, list): + raise InvalidValueError( + 'function "concat" argument must be a list of string expressions: {0}' + .format(safe_repr(argument)), + locator=self.locator) + + string_expressions = [] + for index, an_argument in enumerate(argument): + string_expressions.append(parse_string_expression(context, presentation, 'concat', + index, None, an_argument)) + self.string_expressions = FrozenList(string_expressions) + + @property + def as_raw(self): + string_expressions = [] + for string_expression in self.string_expressions: + if hasattr(string_expression, 'as_raw'): + string_expression = as_raw(string_expression) + string_expressions.append(string_expression) + return {'concat': string_expressions} + + def __evaluate__(self, container_holder): + final = True + value = StringIO() + for e in self.string_expressions: + e, final = evaluate(e, final, container_holder) + if e is not None: + value.write(unicode(e)) + value = value.getvalue() or u'' + return Evaluation(value, final) + + +@implements_specification('4.3.2', 'tosca-simple-1.0') +class Token(Function): + """ + The ``token`` function is used within a TOSCA service template on a string to parse out + (tokenize) substrings separated by one or more token characters within a larger string. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + if (not isinstance(argument, list)) or (len(argument) != 3): + raise InvalidValueError('function "token" argument must be a list of 3 parameters: {0}' + .format(safe_repr(argument)), + locator=self.locator) + + self.string_with_tokens = parse_string_expression(context, presentation, 'token', 0, + 'the string to tokenize', argument[0]) + self.string_of_token_chars = parse_string_expression(context, presentation, 'token', 1, + 'the token separator characters', + argument[1]) + self.substring_index = parse_int(context, presentation, 'token', 2, + 'the 0-based index of the token to return', argument[2]) + + @property + def as_raw(self): + string_with_tokens = self.string_with_tokens + if hasattr(string_with_tokens, 'as_raw'): + string_with_tokens = as_raw(string_with_tokens) + string_of_token_chars = self.string_of_token_chars + if hasattr(string_of_token_chars, 'as_raw'): + string_of_token_chars = as_raw(string_of_token_chars) + return {'token': [string_with_tokens, string_of_token_chars, self.substring_index]} + + def __evaluate__(self, container_holder): + final = True + string_with_tokens, final = evaluate(self.string_with_tokens, final, container_holder) + string_of_token_chars, final = evaluate(self.string_of_token_chars, final, container_holder) + + if string_of_token_chars: + regex = '[' + ''.join(re.escape(c) for c in string_of_token_chars) + ']' + split = re.split(regex, string_with_tokens) + if self.substring_index < len(split): + return Evaluation(split[self.substring_index], final) + + raise CannotEvaluateFunctionException() + + +# +# Property +# + +@implements_specification('4.4.1', 'tosca-simple-1.0') +class GetInput(Function): + """ + The ``get_input`` function is used to retrieve the values of properties declared within the + inputs section of a TOSCA Service Template. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + self.input_property_name = parse_string_expression(context, presentation, 'get_input', + None, 'the input property name', + argument) + + if isinstance(self.input_property_name, basestring): + the_input = context.presentation.get_from_dict('service_template', 'topology_template', + 'inputs', self.input_property_name) + if the_input is None: + raise InvalidValueError( + 'function "get_input" argument is not a valid input name: {0}' + .format(safe_repr(argument)), + locator=self.locator) + + @property + def as_raw(self): + return {'get_input': as_raw(self.input_property_name)} + + def __evaluate__(self, container_holder): + service = container_holder.service + if service is None: + raise CannotEvaluateFunctionException() + + value = service.inputs.get(self.input_property_name) + if value is not None: + value = value.value + return Evaluation(value, False) # We never return final evaluations! + + raise InvalidValueError( + 'function "get_input" argument is not a valid input name: {0}' + .format(safe_repr(self.input_property_name)), + locator=self.locator) + + +@implements_specification('4.4.2', 'tosca-simple-1.0') +class GetProperty(Function): + """ + The ``get_property`` function is used to retrieve property values between modelable entities + defined in the same service template. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + if (not isinstance(argument, list)) or (len(argument) < 2): + raise InvalidValueError( + 'function "get_property" argument must be a list of at least 2 string expressions: ' + '{0}'.format(safe_repr(argument)), + locator=self.locator) + + self.modelable_entity_name = parse_modelable_entity_name(context, presentation, + 'get_property', 0, argument[0]) + # The first of these will be tried as a req-or-cap name: + self.nested_property_name_or_index = argument[1:] + + @property + def as_raw(self): + return {'get_property': [self.modelable_entity_name] + self.nested_property_name_or_index} + + def __evaluate__(self, container_holder): + modelable_entities = get_modelable_entities(container_holder, 'get_property', self.locator, + self.modelable_entity_name) + req_or_cap_name = self.nested_property_name_or_index[0] + + for modelable_entity in modelable_entities: + properties = None + + # First argument refers to a requirement template? + if hasattr(modelable_entity, 'requirement_templates') \ + and modelable_entity.requirement_templates \ + and (req_or_cap_name in [v.name for v in modelable_entity.requirement_templates]): + for requirement in modelable_entity.requirement_templates: + if requirement.name == req_or_cap_name: + # TODO + raise CannotEvaluateFunctionException() + # First argument refers to a capability? + elif hasattr(modelable_entity, 'capabilities') \ + and modelable_entity.capabilities \ + and (req_or_cap_name in modelable_entity.capabilities): + properties = modelable_entity.capabilities[req_or_cap_name].properties + nested_property_name_or_index = self.nested_property_name_or_index[1:] + # First argument refers to a capability template? + elif hasattr(modelable_entity, 'capability_templates') \ + and modelable_entity.capability_templates \ + and (req_or_cap_name in modelable_entity.capability_templates): + properties = modelable_entity.capability_templates[req_or_cap_name].properties + nested_property_name_or_index = self.nested_property_name_or_index[1:] + else: + properties = modelable_entity.properties + nested_property_name_or_index = self.nested_property_name_or_index + + evaluation = get_modelable_entity_parameter(modelable_entity, properties, + nested_property_name_or_index) + if evaluation is not None: + return evaluation + + raise InvalidValueError( + 'function "get_property" could not find "{0}" in modelable entity "{1}"' + .format('.'.join(self.nested_property_name_or_index), self.modelable_entity_name), + locator=self.locator) + + +# +# Attribute +# + +@implements_specification('4.5.1', 'tosca-simple-1.0') +class GetAttribute(Function): + """ + The ``get_attribute`` function is used to retrieve the values of named attributes declared + by the referenced node or relationship template name. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + if (not isinstance(argument, list)) or (len(argument) < 2): + raise InvalidValueError( + 'function "get_attribute" argument must be a list of at least 2 string expressions:' + ' {0}'.format(safe_repr(argument)), + locator=self.locator) + + self.modelable_entity_name = parse_modelable_entity_name(context, presentation, + 'get_attribute', 0, argument[0]) + # The first of these will be tried as a req-or-cap name: + self.nested_attribute_name_or_index = argument[1:] + + @property + def as_raw(self): + return {'get_attribute': [self.modelable_entity_name] + self.nested_attribute_name_or_index} + + def __evaluate__(self, container_holder): + modelable_entities = get_modelable_entities(container_holder, 'get_attribute', self.locator, + self.modelable_entity_name) + for modelable_entity in modelable_entities: + attributes = modelable_entity.attributes + nested_attribute_name_or_index = self.nested_attribute_name_or_index + evaluation = get_modelable_entity_parameter(modelable_entity, attributes, + nested_attribute_name_or_index) + if evaluation is not None: + evaluation.final = False # We never return final evaluations! + return evaluation + + raise InvalidValueError( + 'function "get_attribute" could not find "{0}" in modelable entity "{1}"' + .format('.'.join(self.nested_attribute_name_or_index), self.modelable_entity_name), + locator=self.locator) + + +# +# Operation +# + +@implements_specification('4.6.1', 'tosca-simple-1.0') # pylint: disable=abstract-method +class GetOperationOutput(Function): + """ + The ``get_operation_output`` function is used to retrieve the values of variables exposed / + exported from an interface operation. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + if (not isinstance(argument, list)) or (len(argument) != 4): + raise InvalidValueError( + 'function "get_operation_output" argument must be a list of 4 parameters: {0}' + .format(safe_repr(argument)), + locator=self.locator) + + self.modelable_entity_name = parse_string_expression(context, presentation, + 'get_operation_output', 0, + 'modelable entity name', argument[0]) + self.interface_name = parse_string_expression(context, presentation, 'get_operation_output', + 1, 'the interface name', argument[1]) + self.operation_name = parse_string_expression(context, presentation, 'get_operation_output', + 2, 'the operation name', argument[2]) + self.output_variable_name = parse_string_expression(context, presentation, + 'get_operation_output', 3, + 'the output name', argument[3]) + + @property + def as_raw(self): + interface_name = self.interface_name + if hasattr(interface_name, 'as_raw'): + interface_name = as_raw(interface_name) + operation_name = self.operation_name + if hasattr(operation_name, 'as_raw'): + operation_name = as_raw(operation_name) + output_variable_name = self.output_variable_name + if hasattr(output_variable_name, 'as_raw'): + output_variable_name = as_raw(output_variable_name) + return {'get_operation_output': [self.modelable_entity_name, interface_name, operation_name, + output_variable_name]} + + +# +# Navigation +# + +@implements_specification('4.7.1', 'tosca-simple-1.0') +class GetNodesOfType(Function): + """ + The ``get_nodes_of_type`` function can be used to retrieve a list of all known instances of + nodes of the declared Node Type. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + self.node_type_name = parse_string_expression(context, presentation, 'get_nodes_of_type', + None, 'the node type name', argument) + + if isinstance(self.node_type_name, basestring): + node_types = context.presentation.get('service_template', 'node_types') + if (node_types is None) or (self.node_type_name not in node_types): + raise InvalidValueError( + 'function "get_nodes_of_type" argument is not a valid node type name: {0}' + .format(safe_repr(argument)), + locator=self.locator) + + @property + def as_raw(self): + node_type_name = self.node_type_name + if hasattr(node_type_name, 'as_raw'): + node_type_name = as_raw(node_type_name) + return {'get_nodes_of_type': node_type_name} + + def __evaluate__(self, container): + pass + + +# +# Artifact +# + +@implements_specification('4.8.1', 'tosca-simple-1.0') # pylint: disable=abstract-method +class GetArtifact(Function): + """ + The ``get_artifact`` function is used to retrieve artifact location between modelable + entities defined in the same service template. + """ + + def __init__(self, context, presentation, argument): + self.locator = presentation._locator + + if (not isinstance(argument, list)) or (len(argument) < 2) or (len(argument) > 4): + raise InvalidValueError( + 'function "get_artifact" argument must be a list of 2 to 4 parameters: {0}' + .format(safe_repr(argument)), + locator=self.locator) + + self.modelable_entity_name = parse_string_expression(context, presentation, 'get_artifact', + 0, 'modelable entity name', + argument[0]) + self.artifact_name = parse_string_expression(context, presentation, 'get_artifact', 1, + 'the artifact name', argument[1]) + self.location = parse_string_expression(context, presentation, 'get_artifact', 2, + 'the location or "LOCAL_FILE"', argument[2]) + self.remove = parse_bool(context, presentation, 'get_artifact', 3, 'the removal flag', + argument[3]) + + @property + def as_raw(self): + artifact_name = self.artifact_name + if hasattr(artifact_name, 'as_raw'): + artifact_name = as_raw(artifact_name) + location = self.location + if hasattr(location, 'as_raw'): + location = as_raw(location) + return {'get_artifacts': [self.modelable_entity_name, artifact_name, location, self.remove]} + + +# +# Utils +# + +def get_function(context, presentation, value): + functions = context.presentation.presenter.functions + if isinstance(value, dict) and (len(value) == 1): + key = value.keys()[0] + if key in functions: + try: + return True, functions[key](context, presentation, value[key]) + except InvalidValueError as e: + context.validation.report(issue=e.issue) + return True, None + return False, None + + +def parse_string_expression(context, presentation, name, index, explanation, value): # pylint: disable=unused-argument + is_function, func = get_function(context, presentation, value) + if is_function: + return func + else: + value = str(value) + return value + + +def parse_int(context, presentation, name, index, explanation, value): # pylint: disable=unused-argument + if not isinstance(value, int): + try: + value = int(value) + except ValueError: + raise invalid_value(name, index, 'an integer', explanation, value, + presentation._locator) + return value + + +def parse_bool(context, presentation, name, index, explanation, value): # pylint: disable=unused-argument + if not isinstance(value, bool): + raise invalid_value(name, index, 'a boolean', explanation, value, presentation._locator) + return value + + +def parse_modelable_entity_name(context, presentation, name, index, value): + value = parse_string_expression(context, presentation, name, index, 'the modelable entity name', + value) + if value == 'SELF': + the_self, _ = parse_self(presentation) + if the_self is None: + raise invalid_modelable_entity_name(name, index, value, presentation._locator, + 'a node template or a relationship template') + elif value == 'HOST': + _, self_variant = parse_self(presentation) + if self_variant != 'node_template': + raise invalid_modelable_entity_name(name, index, value, presentation._locator, + 'a node template') + elif (value == 'SOURCE') or (value == 'TARGET'): + _, self_variant = parse_self(presentation) + if self_variant != 'relationship_template': + raise invalid_modelable_entity_name(name, index, value, presentation._locator, + 'a relationship template') + elif isinstance(value, basestring): + node_templates = \ + context.presentation.get('service_template', 'topology_template', 'node_templates') \ + or {} + relationship_templates = \ + context.presentation.get('service_template', 'topology_template', + 'relationship_templates') \ + or {} + if (value not in node_templates) and (value not in relationship_templates): + raise InvalidValueError( + 'function "{0}" parameter {1:d} is not a valid modelable entity name: {2}' + .format(name, index + 1, safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + return value + + +def parse_self(presentation): + from ..types import (NodeType, RelationshipType) + from ..templates import ( + NodeTemplate as NodeTemplatePresentation, + RelationshipTemplate as RelationshipTemplatePresentation + ) + + if presentation is None: + return None, None + elif isinstance(presentation, NodeTemplatePresentation) or isinstance(presentation, NodeType): + return presentation, 'node_template' + elif isinstance(presentation, RelationshipTemplatePresentation) \ + or isinstance(presentation, RelationshipType): + return presentation, 'relationship_template' + else: + return parse_self(presentation._container) + + +def evaluate(value, final, container_holder): + """ + Calls ``__evaluate__`` and passes on ``final`` state. + """ + + if hasattr(value, '__evaluate__'): + value = value.__evaluate__(container_holder) + if not value.final: + final = False + return value.value, final + else: + return value, final + + +@implements_specification('4.1', 'tosca-simple-1.0') +def get_modelable_entities(container_holder, name, locator, modelable_entity_name): + """ + The following keywords MAY be used in some TOSCA function in place of a TOSCA Node or + Relationship Template name. + """ + + if modelable_entity_name == 'SELF': + return get_self(container_holder, name, locator) + elif modelable_entity_name == 'HOST': + return get_hosts(container_holder, name, locator) + elif modelable_entity_name == 'SOURCE': + return get_source(container_holder, name, locator) + elif modelable_entity_name == 'TARGET': + return get_target(container_holder, name, locator) + elif isinstance(modelable_entity_name, basestring): + modelable_entities = [] + + service = container_holder.service + if service is not None: + for node in service.nodes.itervalues(): + if node.node_template.name == modelable_entity_name: + modelable_entities.append(node) + else: + service_template = container_holder.service_template + if service_template is not None: + for node_template in service_template.node_templates.itervalues(): + if node_template.name == modelable_entity_name: + modelable_entities.append(node_template) + + if not modelable_entities: + raise CannotEvaluateFunctionException() + + return modelable_entities + + raise InvalidValueError('function "{0}" could not find modelable entity "{1}"' + .format(name, modelable_entity_name), + locator=locator) + + +def get_self(container_holder, name, locator): + """ + A TOSCA orchestrator will interpret this keyword as the Node or Relationship Template instance + that contains the function at the time the function is evaluated. + """ + + container = container_holder.container + if (not isinstance(container, Node)) and \ + (not isinstance(container, NodeTemplate)) and \ + (not isinstance(container, Relationship)) and \ + (not isinstance(container, RelationshipTemplate)): + raise InvalidValueError('function "{0}" refers to "SELF" but it is not contained in ' + 'a node or a relationship: {1}'.format(name, + full_type_name(container)), + locator=locator) + + return [container] + + +def get_hosts(container_holder, name, locator): + """ + A TOSCA orchestrator will interpret this keyword to refer to the all nodes that "host" the node + using this reference (i.e., as identified by its HostedOn relationship). + + Specifically, TOSCA orchestrators that encounter this keyword when evaluating the get_attribute + or ``get_property`` functions SHALL search each node along the "HostedOn" relationship chain + starting at the immediate node that hosts the node where the function was evaluated (and then + that node's host node, and so forth) until a match is found or the "HostedOn" relationship chain + ends. + """ + + container = container_holder.container + if (not isinstance(container, Node)) and (not isinstance(container, NodeTemplate)): + raise InvalidValueError('function "{0}" refers to "HOST" but it is not contained in ' + 'a node: {1}'.format(name, full_type_name(container)), + locator=locator) + + if not isinstance(container, Node): + # NodeTemplate does not have "host"; we'll wait until instantiation + raise CannotEvaluateFunctionException() + + host = container.host + if host is None: + # We might have a host later + raise CannotEvaluateFunctionException() + + return [host] + + +def get_source(container_holder, name, locator): + """ + A TOSCA orchestrator will interpret this keyword as the Node Template instance that is at the + source end of the relationship that contains the referencing function. + """ + + container = container_holder.container + if (not isinstance(container, Relationship)) and \ + (not isinstance(container, RelationshipTemplate)): + raise InvalidValueError('function "{0}" refers to "SOURCE" but it is not contained in ' + 'a relationship: {1}'.format(name, full_type_name(container)), + locator=locator) + + if not isinstance(container, RelationshipTemplate): + # RelationshipTemplate does not have "source_node"; we'll wait until instantiation + raise CannotEvaluateFunctionException() + + return [container.source_node] + + +def get_target(container_holder, name, locator): + """ + A TOSCA orchestrator will interpret this keyword as the Node Template instance that is at the + target end of the relationship that contains the referencing function. + """ + + container = container_holder.container + if (not isinstance(container, Relationship)) and \ + (not isinstance(container, RelationshipTemplate)): + raise InvalidValueError('function "{0}" refers to "TARGET" but it is not contained in ' + 'a relationship: {1}'.format(name, full_type_name(container)), + locator=locator) + + if not isinstance(container, RelationshipTemplate): + # RelationshipTemplate does not have "target_node"; we'll wait until instantiation + raise CannotEvaluateFunctionException() + + return [container.target_node] + + +def get_modelable_entity_parameter(modelable_entity, parameters, nested_parameter_name_or_index): + if not parameters: + return Evaluation(None, True) + + found = True + final = True + value = parameters + + for name_or_index in nested_parameter_name_or_index: + if (isinstance(value, dict) and (name_or_index in value)) \ + or ((isinstance(value, list) and (name_or_index < len(value)))): + value = value[name_or_index] # Parameter + # We are not using Parameter.value, but rather Parameter._value, because we want to make + # sure to get "final" (it is swallowed by Parameter.value) + value, final = evaluate(value._value, final, value) + else: + found = False + break + + return Evaluation(value, final) if found else None + + +def invalid_modelable_entity_name(name, index, value, locator, contexts): + return InvalidValueError('function "{0}" parameter {1:d} can be "{2}" only in {3}' + .format(name, index + 1, value, contexts), + locator=locator, level=Issue.FIELD) + + +def invalid_value(name, index, the_type, explanation, value, locator): + return InvalidValueError( + 'function "{0}" {1} is not {2}{3}: {4}' + .format(name, + 'parameter {0:d}'.format(index + 1) if index is not None else 'argument', + the_type, + ', {0}'.format(explanation) if explanation is not None else '', + safe_repr(value)), + locator=locator, level=Issue.FIELD) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py new file mode 100644 index 0000000..23a03b7 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py @@ -0,0 +1,530 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import (merge, deepcopy_with_locators, OrderedDict) +from aria.parser.presentation import get_locator +from aria.parser.validation import Issue + +from .parameters import (coerce_parameter_value, convert_parameter_definitions_to_values) + + +# +# InterfaceType +# + +def get_inherited_operations(context, presentation): + """ + Returns our operation definitions added on top of those of our parent, if we have one + (recursively). + + Allows overriding all aspects of parent operations except input data types. + """ + + # Get operations from parent + parent = presentation._get_parent(context) + operations = get_inherited_operations(context, parent) if parent is not None else OrderedDict() + + # Add/merge our operations + our_operations = presentation.operations # OperationDefinition + merge_operation_definitions(context, operations, our_operations, presentation._name, + presentation, 'type') + + for operation in operations.itervalues(): + operation._reset_method_cache() + + return operations + + +# +# InterfaceDefinition +# + +def get_and_override_input_definitions_from_type(context, presentation): + """ + Returns our input definitions added on top of those of the interface type, if specified. + + Allows overriding all aspects of parent interface type inputs except data types. + """ + + inputs = OrderedDict() + + # Get inputs from type + the_type = presentation._get_type(context) # InterfaceType + type_inputs = the_type._get_inputs(context) if the_type is not None else None + if type_inputs: + for input_name, type_input in type_inputs.iteritems(): + inputs[input_name] = type_input._clone(presentation) + + # Add/merge our inputs + our_inputs = presentation.inputs # PropertyDefinition + if our_inputs: + merge_input_definitions(context, inputs, our_inputs, presentation._name, None, presentation, + 'definition') + + return inputs + + +def get_and_override_operation_definitions_from_type(context, presentation): + """ + Returns our operation definitions added on top of those of the interface type, if specified. + + Allows overriding all aspects of parent interface type inputs except data types. + """ + + operations = OrderedDict() + + # Get operations from type + the_type = presentation._get_type(context) # InterfaceType + type_operations = the_type._get_operations(context) if the_type is not None else None + if type_operations: + for operations_name, type_operation in type_operations.iteritems(): + operations[operations_name] = type_operation._clone(presentation) + + # Add/merge our operations + our_operations = presentation.operations # OperationDefinition + merge_operation_definitions(context, operations, our_operations, presentation._name, + presentation, 'definition') + + return operations + + +# +# NodeType, RelationshipType, GroupType +# + +def get_inherited_interface_definitions(context, presentation, type_name, for_presentation=None): + """ + Returns our interface definitions added on top of those of our parent, if we have one + (recursively). + + Allows overriding all aspects of parent interfaces except interface and operation input data + types. + """ + + if for_presentation is None: + for_presentation = presentation + + # Get interfaces from parent + parent = presentation._get_parent(context) + interfaces = get_inherited_interface_definitions(context, parent, type_name, for_presentation) \ + if parent is not None else OrderedDict() + + # Add/merge interfaces from their types + merge_interface_definitions_from_their_types(context, interfaces, presentation) + + # Add/merge our interfaces + our_interfaces = presentation.interfaces + merge_interface_definitions(context, interfaces, our_interfaces, presentation, for_presentation) + + return interfaces + + +# +# NodeTemplate, RelationshipTemplate, GroupTemplate +# + +def get_template_interfaces(context, presentation, type_name): + """ + Returns the assigned interface_template values while making sure they are defined in the type. + This includes the interfaces themselves, their operations, and inputs for interfaces and + operations. + + Interface and operation inputs' default values, if available, will be used if we did not assign + them. + + Makes sure that required inputs indeed end up with a value. + + This code is especially complex due to the many levels of nesting involved. + """ + + template_interfaces = OrderedDict() + + the_type = presentation._get_type(context) # NodeType, RelationshipType, GroupType + # InterfaceDefinition (or InterfaceAssignment in the case of RelationshipTemplate): + interface_definitions = the_type._get_interfaces(context) if the_type is not None else None + + # Copy over interfaces from the type (will initialize inputs with default values) + if interface_definitions is not None: + for interface_name, interface_definition in interface_definitions.iteritems(): + # Note that in the case of a RelationshipTemplate, we will already have the values as + # InterfaceAssignment. It will not be converted, just cloned. + template_interfaces[interface_name] = \ + convert_interface_definition_from_type_to_template(context, interface_definition, + presentation) + + # Fill in our interfaces + our_interface_assignments = presentation.interfaces + if our_interface_assignments: + # InterfaceAssignment: + for interface_name, our_interface_assignment in our_interface_assignments.iteritems(): + if interface_name in template_interfaces: + interface_assignment = template_interfaces[interface_name] # InterfaceAssignment + # InterfaceDefinition (or InterfaceAssignment in the case of RelationshipTemplate): + interface_definition = interface_definitions[interface_name] + merge_interface(context, presentation, interface_assignment, + our_interface_assignment, interface_definition, interface_name) + else: + context.validation.report( + 'interface definition "%s" not declared at %s "%s" in "%s"' + % (interface_name, type_name, presentation.type, presentation._fullname), + locator=our_interface_assignment._locator, level=Issue.BETWEEN_TYPES) + + # Check that there are no required inputs that we haven't assigned + for interface_name, interface_template in template_interfaces.iteritems(): + if interface_name in interface_definitions: + # InterfaceDefinition (or InterfaceAssignment in the case of RelationshipTemplate): + interface_definition = interface_definitions[interface_name] + our_interface_assignment = our_interface_assignments.get(interface_name) \ + if our_interface_assignments is not None else None + validate_required_inputs(context, presentation, interface_template, + interface_definition, our_interface_assignment, interface_name) + + return template_interfaces + + +# +# Utils +# + +def convert_interface_definition_from_type_to_template(context, presentation, container): + from ..assignments import InterfaceAssignment + + if isinstance(presentation, InterfaceAssignment): + # Nothing to convert, so just clone + return presentation._clone(container) + + raw = convert_interface_definition_from_type_to_raw_template(context, presentation) + return InterfaceAssignment(name=presentation._name, raw=raw, container=container) + + +def convert_interface_definition_from_type_to_raw_template(context, presentation): # pylint: disable=invalid-name + raw = OrderedDict() + + # Copy default values for inputs + interface_inputs = presentation._get_inputs(context) + if interface_inputs is not None: + raw['inputs'] = convert_parameter_definitions_to_values(context, interface_inputs) + + # Copy operations + operations = presentation._get_operations(context) + if operations: + for operation_name, operation in operations.iteritems(): + raw[operation_name] = OrderedDict() + description = operation.description + if description is not None: + raw[operation_name]['description'] = deepcopy_with_locators(description._raw) + implementation = operation.implementation + if implementation is not None: + raw[operation_name]['implementation'] = deepcopy_with_locators(implementation._raw) + inputs = operation.inputs + if inputs is not None: + raw[operation_name]['inputs'] = convert_parameter_definitions_to_values(context, + inputs) + + return raw + + +def convert_requirement_interface_definitions_from_type_to_raw_template(context, raw_requirement, # pylint: disable=invalid-name + interface_definitions): + if not interface_definitions: + return + if 'interfaces' not in raw_requirement: + raw_requirement['interfaces'] = OrderedDict() + for interface_name, interface_definition in interface_definitions.iteritems(): + raw_interface = convert_interface_definition_from_type_to_raw_template(context, + interface_definition) + if interface_name in raw_requirement['interfaces']: + merge(raw_requirement['interfaces'][interface_name], raw_interface) + else: + raw_requirement['interfaces'][interface_name] = raw_interface + + +def merge_interface(context, presentation, interface_assignment, our_interface_assignment, + interface_definition, interface_name): + # Assign/merge interface inputs + assign_raw_inputs(context, interface_assignment._raw, our_interface_assignment.inputs, + interface_definition._get_inputs(context), interface_name, None, presentation) + + # Assign operation implementations and inputs + our_operation_templates = our_interface_assignment.operations # OperationAssignment + # OperationDefinition or OperationAssignment: + operation_definitions = interface_definition._get_operations(context) \ + if hasattr(interface_definition, '_get_operations') else interface_definition.operations + if our_operation_templates: + # OperationAssignment: + for operation_name, our_operation_template in our_operation_templates.iteritems(): + operation_definition = operation_definitions.get(operation_name) # OperationDefinition + + our_input_assignments = our_operation_template.inputs + our_implementation = our_operation_template.implementation + + if operation_definition is None: + context.validation.report( + 'interface definition "%s" refers to an unknown operation "%s" in "%s"' + % (interface_name, operation_name, presentation._fullname), + locator=our_operation_template._locator, level=Issue.BETWEEN_TYPES) + + if (our_input_assignments is not None) or (our_implementation is not None): + # Make sure we have the dict + if (operation_name not in interface_assignment._raw) \ + or (interface_assignment._raw[operation_name] is None): + interface_assignment._raw[operation_name] = OrderedDict() + + if our_implementation is not None: + interface_assignment._raw[operation_name]['implementation'] = \ + deepcopy_with_locators(our_implementation._raw) + + # Assign/merge operation inputs + input_definitions = operation_definition.inputs \ + if operation_definition is not None else None + assign_raw_inputs(context, interface_assignment._raw[operation_name], + our_input_assignments, input_definitions, interface_name, + operation_name, presentation) + + +def merge_raw_input_definition(context, the_raw_input, our_input, interface_name, operation_name, + presentation, type_name): + # Check if we changed the type + # TODO: allow a sub-type? + input_type1 = the_raw_input.get('type') + input_type2 = our_input.type + if input_type1 != input_type2: + if operation_name is not None: + context.validation.report( + 'interface %s "%s" changes operation input "%s.%s" type from "%s" to "%s" in "%s"' + % (type_name, interface_name, operation_name, our_input._name, input_type1, + input_type2, presentation._fullname), + locator=input_type2._locator, level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'interface %s "%s" changes input "%s" type from "%s" to "%s" in "%s"' + % (type_name, interface_name, our_input._name, input_type1, input_type2, + presentation._fullname), + locator=input_type2._locator, level=Issue.BETWEEN_TYPES) + + # Merge + merge(the_raw_input, our_input._raw) + + +def merge_input_definitions(context, inputs, our_inputs, interface_name, operation_name, + presentation, type_name): + for input_name, our_input in our_inputs.iteritems(): + if input_name in inputs: + merge_raw_input_definition(context, inputs[input_name]._raw, our_input, interface_name, + operation_name, presentation, type_name) + else: + inputs[input_name] = our_input._clone(presentation) + + +def merge_raw_input_definitions(context, raw_inputs, our_inputs, interface_name, operation_name, + presentation, type_name): + for input_name, our_input in our_inputs.iteritems(): + if input_name in raw_inputs: + merge_raw_input_definition(context, raw_inputs[input_name], our_input, interface_name, + operation_name, presentation, type_name) + else: + raw_inputs[input_name] = deepcopy_with_locators(our_input._raw) + + +def merge_raw_operation_definition(context, raw_operation, our_operation, interface_name, + presentation, type_name): + if not isinstance(our_operation._raw, dict): + # Convert short form to long form + raw_operation['implementation'] = deepcopy_with_locators(our_operation._raw) + return + + # Add/merge inputs + our_operation_inputs = our_operation.inputs + if our_operation_inputs: + # Make sure we have the dict + if ('inputs' not in raw_operation) or (raw_operation.get('inputs') is None): + raw_operation['inputs'] = OrderedDict() + + merge_raw_input_definitions(context, raw_operation['inputs'], our_operation_inputs, + interface_name, our_operation._name, presentation, type_name) + + # Override the description + if our_operation._raw.get('description') is not None: + raw_operation['description'] = deepcopy_with_locators(our_operation._raw['description']) + + # Add/merge implementation + if our_operation._raw.get('implementation') is not None: + if raw_operation.get('implementation') is not None: + merge(raw_operation['implementation'], + deepcopy_with_locators(our_operation._raw['implementation'])) + else: + raw_operation['implementation'] = \ + deepcopy_with_locators(our_operation._raw['implementation']) + + +def merge_operation_definitions(context, operations, our_operations, interface_name, presentation, + type_name): + if not our_operations: + return + for operation_name, our_operation in our_operations.iteritems(): + if operation_name in operations: + merge_raw_operation_definition(context, operations[operation_name]._raw, our_operation, + interface_name, presentation, type_name) + else: + operations[operation_name] = our_operation._clone(presentation) + + +def merge_raw_operation_definitions(context, raw_operations, our_operations, interface_name, + presentation, type_name): + for operation_name, our_operation in our_operations.iteritems(): + if operation_name in raw_operations: + raw_operation = raw_operations[operation_name] + if isinstance(raw_operation, basestring): + # Convert short form to long form + raw_operations[operation_name] = OrderedDict((('implementation', raw_operation),)) + raw_operation = raw_operations[operation_name] + merge_raw_operation_definition(context, raw_operation, our_operation, interface_name, + presentation, type_name) + else: + raw_operations[operation_name] = deepcopy_with_locators(our_operation._raw) + + +# From either an InterfaceType or an InterfaceDefinition: +def merge_interface_definition(context, interface, our_source, presentation, type_name): + if hasattr(our_source, 'type'): + # Check if we changed the interface type + type1 = interface._get_type(context) + type2 = our_source._get_type(context) + + if (type2 is not None) and not type1._is_descendant(context, type2): + context.validation.report( + 'interface definition type "{0}" is not a descendant of overridden ' + 'interface definition type "{1}"' \ + .format(type1._name, type2._name), + locator=our_source._locator, level=Issue.BETWEEN_TYPES) + + # Add/merge inputs + our_interface_inputs = our_source._get_inputs(context) \ + if hasattr(our_source, '_get_inputs') else our_source.inputs + if our_interface_inputs: + # Make sure we have the dict + if ('inputs' not in interface._raw) or (interface._raw.get('inputs') is None): + interface._raw['inputs'] = OrderedDict() + + merge_raw_input_definitions(context, interface._raw['inputs'], our_interface_inputs, + our_source._name, None, presentation, type_name) + + # Add/merge operations + our_operations = our_source._get_operations(context) \ + if hasattr(our_source, '_get_operations') else our_source.operations + if our_operations is not None: + merge_raw_operation_definitions(context, interface._raw, our_operations, our_source._name, + presentation, type_name) + + +def merge_interface_definitions(context, interfaces, our_interfaces, presentation, + for_presentation=None): + if not our_interfaces: + return + for name, our_interface in our_interfaces.iteritems(): + if name in interfaces: + merge_interface_definition(context, interfaces[name], our_interface, presentation, + 'definition') + else: + interfaces[name] = our_interface._clone(for_presentation) + + +def merge_interface_definitions_from_their_types(context, interfaces, presentation): + for interface in interfaces.itervalues(): + the_type = interface._get_type(context) # InterfaceType + if the_type is not None: + merge_interface_definition(context, interface, the_type, presentation, 'type') + + +def assign_raw_inputs(context, values, assignments, definitions, interface_name, operation_name, + presentation): + if not assignments: + return + + # Make sure we have the dict + if ('inputs' not in values) or (values['inputs'] is None): + values['inputs'] = OrderedDict() + + # Assign inputs + for input_name, assignment in assignments.iteritems(): + if (definitions is not None) and (input_name not in definitions): + if operation_name is not None: + context.validation.report( + 'interface definition "%s" assigns a value to an unknown operation input' + ' "%s.%s" in "%s"' + % (interface_name, operation_name, input_name, presentation._fullname), + locator=assignment._locator, level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'interface definition "%s" assigns a value to an unknown input "%s" in "%s"' + % (interface_name, input_name, presentation._fullname), + locator=assignment._locator, level=Issue.BETWEEN_TYPES) + + definition = definitions.get(input_name) if definitions is not None else None + + # Note: default value has already been assigned + + # Coerce value + values['inputs'][input_name] = coerce_parameter_value(context, assignment, definition, + assignment.value) + + +def validate_required_inputs(context, presentation, assignment, definition, original_assignment, + interface_name, operation_name=None): + # The validation of the `required` field of inputs that belong to operations and interfaces + # (as opposed to topology template and workflow inputs) is done only in the parsing stage. + # This reasoning follows the TOSCA spirit, where anything that is declared as required in the + # type, must be assigned in the corresponding template. + input_definitions = definition.inputs + if input_definitions: + for input_name, input_definition in input_definitions.iteritems(): + if input_definition.required: + prop = assignment.inputs.get(input_name) \ + if ((assignment is not None) and (assignment.inputs is not None)) else None + value = prop.value if prop is not None else None + value = value.value if value is not None else None + if value is None: + if operation_name is not None: + context.validation.report( + 'interface definition "%s" does not assign a value to a required' + ' operation input "%s.%s" in "%s"' + % (interface_name, operation_name, input_name, presentation._fullname), + locator=get_locator(original_assignment, presentation._locator), + level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'interface definition "%s" does not assign a value to a required input' + ' "%s" in "%s"' + % (interface_name, input_name, presentation._fullname), + locator=get_locator(original_assignment, presentation._locator), + level=Issue.BETWEEN_TYPES) + + if operation_name is not None: + return + + assignment_operations = assignment.operations + operation_definitions = definition._get_operations(context) + if operation_definitions: + for operation_name, operation_definition in operation_definitions.iteritems(): + assignment_operation = assignment_operations.get(operation_name) \ + if assignment_operations is not None else None + original_operation = \ + original_assignment.operations.get(operation_name, original_assignment) \ + if (original_assignment is not None) \ + and (original_assignment.operations is not None) \ + else original_assignment + validate_required_inputs(context, presentation, assignment_operation, + operation_definition, original_operation, interface_name, + operation_name) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py new file mode 100644 index 0000000..9bafeec --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py @@ -0,0 +1,230 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import (merge, deepcopy_with_locators, OrderedDict) +from aria.utils.formatting import pluralize +from aria.parser.presentation import Value +from aria.parser.validation import Issue + +from .data_types import (coerce_value, get_primitive_data_type) +from ..presentation.types import get_type_by_name + + +# +# ArtifactType, DataType, CapabilityType, RelationshipType, NodeType, GroupType, PolicyType +# + +def get_inherited_parameter_definitions(context, presentation, field_name, for_presentation=None): + """ + Returns our parameter definitions added on top of those of our parent, if we have one + (recursively). + + Allows overriding all aspects of parent properties except data type. + """ + + if for_presentation is None: + for_presentation = presentation + + # Get definitions from parent + # If we inherit from a primitive, it does not have a parent: + parent = presentation._get_parent(context) if hasattr(presentation, '_get_parent') else None + definitions = get_inherited_parameter_definitions(context, parent, field_name, + for_presentation) \ + if parent is not None else OrderedDict() + + # Add/merge our definitions + # If we inherit from a primitive, it does not have our field + our_definitions = getattr(presentation, field_name, None) + if our_definitions: + our_definitions_clone = OrderedDict() + for name, our_definition in our_definitions.iteritems(): + our_definitions_clone[name] = our_definition._clone(for_presentation) + our_definitions = our_definitions_clone + merge_parameter_definitions(context, presentation, definitions, our_definitions, field_name) + + for definition in definitions.itervalues(): + definition._reset_method_cache() + + return definitions + + +# +# NodeTemplate, RelationshipTemplate, GroupTemplate, PolicyTemplate +# + +def get_assigned_and_defined_parameter_values(context, presentation, field_name): + """ + Returns the assigned parameter values while making sure they are defined in our type. + + The parameter definition's default value, if available, will be used if we did not assign it. + + Makes sure that required parameters indeed end up with a value. + """ + + values = OrderedDict() + + the_type = presentation._get_type(context) + field_name_plural = pluralize(field_name) + assignments = getattr(presentation, field_name_plural) + get_fn_name = '_get_{0}'.format(field_name_plural) + definitions = getattr(the_type, get_fn_name)(context) if the_type is not None else None + + # Fill in our assignments, but make sure they are defined + if assignments: + for name, value in assignments.iteritems(): + if (definitions is not None) and (name in definitions): + definition = definitions[name] + values[name] = coerce_parameter_value(context, value, definition, value.value) + else: + context.validation.report('assignment to undefined {0} "{1}" in "{2}"' + .format(field_name, name, presentation._fullname), + locator=value._locator, level=Issue.BETWEEN_TYPES) + + # Fill in defaults from the definitions + if definitions: + for name, definition in definitions.iteritems(): + # Note: attributes will always have a default value, even if it's None + if (name not in values) and \ + (('default' in definition._raw) or (field_name == 'attribute')): + values[name] = coerce_parameter_value(context, presentation, definition, + definition.default) + + validate_required_values(context, presentation, values, definitions) + + # Fill in nulls for missing values that are *not* required + if definitions: + for name, definition in definitions.iteritems(): + if (name not in values) and not getattr(definition, 'required', False): + values[name] = coerce_parameter_value(context, presentation, definition, None) + + return values + + +# +# TopologyTemplate +# + +def get_parameter_values(context, presentation, field_name): + values = OrderedDict() + + parameters = getattr(presentation, field_name) + + # Fill in defaults and values + if parameters: + for name, parameter in parameters.iteritems(): + if values.get(name) is None: + if hasattr(parameter, 'value') and (parameter.value is not None): + # For parameters only: + values[name] = coerce_parameter_value(context, presentation, parameter, + parameter.value) + else: + default = parameter.default if hasattr(parameter, 'default') else None + values[name] = coerce_parameter_value(context, presentation, parameter, default) + + return values + + +# +# Utils +# + +def validate_required_values(context, presentation, values, definitions): + """ + Check if required properties have not been assigned. + """ + + if not definitions: + return + for name, definition in definitions.iteritems(): + if getattr(definition, 'required', False) and \ + ((values is None) or (values.get(name) is None)): + context.validation.report('required property "%s" is not assigned a value in "%s"' + % (name, presentation._fullname), + locator=presentation._get_child_locator('properties'), + level=Issue.BETWEEN_TYPES) + + +def merge_raw_parameter_definition(context, presentation, raw_property_definition, + our_property_definition, field_name, property_name): + # Check if we changed the parameter type + type1_name = raw_property_definition.get('type') + type1 = get_type_by_name(context, type1_name, 'data_types') + if type1 is None: + type1 = get_primitive_data_type(type1_name) + our_property_definition._reset_method_cache() + type2 = our_property_definition._get_type(context) + + if type1 != type2: + if not hasattr(type1, '_is_descendant') or not type1._is_descendant(context, type2): + context.validation.report( + 'property definition type "{0}" is not a descendant of overridden ' + 'property definition type "{1}"' \ + .format(type1_name, type2._name), + locator=presentation._get_child_locator(field_name, property_name), + level=Issue.BETWEEN_TYPES) + + merge(raw_property_definition, our_property_definition._raw) + + +def merge_raw_parameter_definitions(context, presentation, raw_property_definitions, + our_property_definitions, field_name): + if not our_property_definitions: + return + for property_name, our_property_definition in our_property_definitions.iteritems(): + if property_name in raw_property_definitions: + raw_property_definition = raw_property_definitions[property_name] + merge_raw_parameter_definition(context, presentation, raw_property_definition, + our_property_definition, field_name, property_name) + else: + raw_property_definitions[property_name] = \ + deepcopy_with_locators(our_property_definition._raw) + + +def merge_parameter_definitions(context, presentation, property_definitions, + our_property_definitions, field_name): + if not our_property_definitions: + return + for property_name, our_property_definition in our_property_definitions.iteritems(): + if property_name in property_definitions: + property_definition = property_definitions[property_name] + merge_raw_parameter_definition(context, presentation, property_definition._raw, + our_property_definition, field_name, property_name) + else: + property_definitions[property_name] = our_property_definition + + +# Works on properties, inputs, and parameters +def coerce_parameter_value(context, presentation, definition, value, aspect=None): + the_type = definition._get_type(context) if definition is not None else None + entry_schema = definition.entry_schema if definition is not None else None + constraints = definition._get_constraints(context) \ + if ((definition is not None) and hasattr(definition, '_get_constraints')) else None + value = coerce_value(context, presentation, the_type, entry_schema, constraints, value, aspect) + if (the_type is not None) and hasattr(the_type, '_name'): + type_name = the_type._name + else: + type_name = getattr(definition, 'type', None) + description = getattr(definition, 'description', None) + description = description.value if description is not None else None + required = getattr(definition, 'required', None) + return Value(type_name, value, description, required) + + +def convert_parameter_definitions_to_values(context, definitions): + values = OrderedDict() + for name, definition in definitions.iteritems(): + default = definition.default + values[name] = coerce_parameter_value(context, definition, definition, default) + return values diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py new file mode 100644 index 0000000..0376798 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py @@ -0,0 +1,79 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ..presentation.types import convert_name_to_full_type_name + + +# +# PolicyType +# + +def get_inherited_targets(context, presentation): + """ + Returns our target node types and group types if we have them or those of our parent, if we have + one (recursively). + """ + + parent = presentation._get_parent(context) + + node_types, group_types = get_inherited_targets(context, parent) \ + if parent is not None else ([], []) + + our_targets = presentation.targets + if our_targets: + all_node_types = context.presentation.get('service_template', 'node_types') or {} + all_group_types = context.presentation.get('service_template', 'group_types') or {} + node_types = [] + group_types = [] + + for our_target in our_targets: + if our_target in all_node_types: + our_target = convert_name_to_full_type_name(context, our_target, all_node_types) + node_types.append(all_node_types[our_target]) + elif our_target in all_group_types: + our_target = convert_name_to_full_type_name(context, our_target, all_group_types) + group_types.append(all_group_types[our_target]) + + return node_types, group_types + + +# +# PolicyTemplate +# + +def get_policy_targets(context, presentation): + """ + Returns our target node templates and groups if we have them. + """ + + node_templates = [] + groups = [] + + our_targets = presentation.targets + if our_targets: + all_node_templates = \ + context.presentation.get('service_template', 'topology_template', 'node_templates') \ + or {} + all_groups = \ + context.presentation.get('service_template', 'topology_template', 'groups') \ + or {} + + for our_target in our_targets: + if our_target in all_node_templates: + node_templates.append(all_node_templates[our_target]) + elif our_target in all_groups: + groups.append(all_groups[our_target]) + + return node_templates, groups diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py new file mode 100644 index 0000000..6bdb5b1 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py @@ -0,0 +1,364 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.parser.validation import Issue +from aria.utils.collections import (deepcopy_with_locators, OrderedDict) + +from .parameters import (convert_parameter_definitions_to_values, validate_required_values, + coerce_parameter_value) +from .interfaces import (convert_requirement_interface_definitions_from_type_to_raw_template, + merge_interface_definitions, merge_interface, validate_required_inputs) + + +# +# NodeType +# + +def get_inherited_requirement_definitions(context, presentation): + """ + Returns our requirement definitions added on top of those of our parent, if we have one + (recursively). + + Allows overriding requirement definitions if they have the same name. + """ + + parent = presentation._get_parent(context) + requirement_definitions = get_inherited_requirement_definitions(context, parent) \ + if parent is not None else [] + + our_requirement_definitions = presentation.requirements + if our_requirement_definitions: + for requirement_name, our_requirement_definition in our_requirement_definitions: + # Remove existing requirement definitions of this name if they exist + for name, requirement_definition in requirement_definitions: + if name == requirement_name: + requirement_definitions.remove((name, requirement_definition)) + + requirement_definitions.append((requirement_name, our_requirement_definition)) + + return requirement_definitions + + +# +# NodeTemplate +# + +def get_template_requirements(context, presentation): + """ + Returns our requirements added on top of those of the node type if they exist there. + + If the requirement has a relationship, the relationship properties and interfaces are assigned. + + Returns the assigned property, interface input, and interface operation input values while + making sure they are defined in our type. Default values, if available, will be used if we did + not assign them. Also makes sure that required properties and inputs indeed end up with a value. + """ + + requirement_assignments = [] + + the_type = presentation._get_type(context) # NodeType + requirement_definitions = the_type._get_requirements(context) if the_type is not None else None + + # Add our requirement assignments + our_requirement_assignments = presentation.requirements + if our_requirement_assignments: + add_requirement_assignments(context, presentation, requirement_assignments, + requirement_definitions, our_requirement_assignments) + + # Validate occurrences + if requirement_definitions: + for requirement_name, requirement_definition in requirement_definitions: + # Allowed occurrences + allowed_occurrences = requirement_definition.occurrences + allowed_occurrences = allowed_occurrences if allowed_occurrences is not None else None + + # Count actual occurrences + actual_occurrences = 0 + for name, _ in requirement_assignments: + if name == requirement_name: + actual_occurrences += 1 + + if allowed_occurrences is None: + # If not specified, we interpret this to mean that exactly 1 occurrence is required + if actual_occurrences == 0: + # If it's not there, we will automatically add it (this behavior is not in the + # TOSCA spec, but seems implied) + requirement_assignment, \ + relationship_property_definitions, \ + relationship_interface_definitions = \ + convert_requirement_from_definition_to_assignment(context, + requirement_definition, + None, presentation) + validate_requirement_assignment(context, presentation, requirement_assignment, + relationship_property_definitions, + relationship_interface_definitions) + requirement_assignments.append((requirement_name, requirement_assignment)) + elif actual_occurrences > 1: + context.validation.report( + 'requirement "%s" is allowed only one occurrence in "%s": %d' + % (requirement_name, presentation._fullname, actual_occurrences), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + else: + if not allowed_occurrences.is_in(actual_occurrences): + if allowed_occurrences.value[1] == 'UNBOUNDED': + context.validation.report( + 'requirement "%s" does not have at least %d occurrences in "%s": has %d' + % (requirement_name, allowed_occurrences.value[0], + presentation._fullname, actual_occurrences), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'requirement "%s" is allowed between %d and %d occurrences in "%s":' + ' has %d' + % (requirement_name, allowed_occurrences.value[0], + allowed_occurrences.value[1], presentation._fullname, + actual_occurrences), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + return requirement_assignments + + +# +# Utils +# + +def convert_requirement_from_definition_to_assignment(context, requirement_definition, # pylint: disable=too-many-branches + our_requirement_assignment, container): + from ..assignments import RequirementAssignment + + raw = OrderedDict() + + # Capability type name: + raw['capability'] = deepcopy_with_locators(requirement_definition.capability) + + node_type = requirement_definition._get_node_type(context) + if node_type is not None: + raw['node'] = deepcopy_with_locators(node_type._name) + + relationship_type = None + relationship_template = None + relationship_property_definitions = None + relationship_interface_definitions = None + + # First try to find the relationship if we declared it + # RelationshipAssignment: + our_relationship = our_requirement_assignment.relationship \ + if our_requirement_assignment is not None else None + if our_relationship is not None: + relationship_type, relationship_type_variant = our_relationship._get_type(context) + if relationship_type_variant == 'relationship_template': + relationship_template = relationship_type + relationship_type = relationship_template._get_type(context) + + definition_relationship_type = None + relationship_definition = requirement_definition.relationship # RelationshipDefinition + if relationship_definition is not None: + definition_relationship_type = relationship_definition._get_type(context) + + # If not exists, try at the node type + if relationship_type is None: + relationship_type = definition_relationship_type + else: + # Make sure the type is derived + if not definition_relationship_type._is_descendant(context, relationship_type): + context.validation.report( + 'assigned relationship type "%s" is not a descendant of declared relationship type' + ' "%s"' \ + % (relationship_type._name, definition_relationship_type._name), + locator=container._locator, level=Issue.BETWEEN_TYPES) + + if relationship_type is not None: + raw['relationship'] = OrderedDict() + + type_name = our_relationship.type if our_relationship is not None else None + if type_name is None: + type_name = relationship_type._name + + raw['relationship']['type'] = deepcopy_with_locators(type_name) + + # These are our property definitions + relationship_property_definitions = relationship_type._get_properties(context) + + if relationship_template is not None: + # Property values from template + raw['relationship']['properties'] = relationship_template._get_property_values(context) + else: + if relationship_property_definitions: + # Convert property definitions to values + raw['relationship']['properties'] = \ + convert_parameter_definitions_to_values(context, + relationship_property_definitions) + + # These are our interface definitions + # InterfaceDefinition: + relationship_interface_definitions = OrderedDict(relationship_type._get_interfaces(context)) + + # Convert interface definitions to templates + convert_requirement_interface_definitions_from_type_to_raw_template( + context, + raw['relationship'], + relationship_interface_definitions) + + if relationship_definition: + # Merge extra interface definitions + # InterfaceDefinition: + definition_interface_definitions = relationship_definition.interfaces + merge_interface_definitions(context, relationship_interface_definitions, + definition_interface_definitions, requirement_definition, + container) + + if relationship_template is not None: + # Interfaces from template + interfaces = relationship_template._get_interfaces(context) + if interfaces: + raw['relationship']['interfaces'] = OrderedDict() + for interface_name, interface in interfaces.iteritems(): + raw['relationship']['interfaces'][interface_name] = interface._raw + + return \ + RequirementAssignment(name=requirement_definition._name, raw=raw, container=container), \ + relationship_property_definitions, \ + relationship_interface_definitions + + +def add_requirement_assignments(context, presentation, requirement_assignments, + requirement_definitions, our_requirement_assignments): + for requirement_name, our_requirement_assignment in our_requirement_assignments: + requirement_definition = get_first_requirement(requirement_definitions, requirement_name) + if requirement_definition is not None: + requirement_assignment, \ + relationship_property_definitions, \ + relationship_interface_definitions = \ + convert_requirement_from_definition_to_assignment(context, requirement_definition, + our_requirement_assignment, + presentation) + merge_requirement_assignment(context, + relationship_property_definitions, + relationship_interface_definitions, + requirement_assignment, our_requirement_assignment) + validate_requirement_assignment(context, + our_requirement_assignment.relationship \ + or our_requirement_assignment, + requirement_assignment, + relationship_property_definitions, + relationship_interface_definitions) + requirement_assignments.append((requirement_name, requirement_assignment)) + else: + context.validation.report('requirement "%s" not declared at node type "%s" in "%s"' + % (requirement_name, presentation.type, + presentation._fullname), + locator=our_requirement_assignment._locator, + level=Issue.BETWEEN_TYPES) + + +def merge_requirement_assignment(context, relationship_property_definitions, + relationship_interface_definitions, requirement, our_requirement): + our_capability = our_requirement.capability + if our_capability is not None: + requirement._raw['capability'] = deepcopy_with_locators(our_capability) + + our_node = our_requirement.node + if our_node is not None: + requirement._raw['node'] = deepcopy_with_locators(our_node) + + our_node_filter = our_requirement.node_filter + if our_node_filter is not None: + requirement._raw['node_filter'] = deepcopy_with_locators(our_node_filter._raw) + + our_relationship = our_requirement.relationship # RelationshipAssignment + if (our_relationship is not None) and (our_relationship.type is None): + # Make sure we have a dict + if 'relationship' not in requirement._raw: + requirement._raw['relationship'] = OrderedDict() + + merge_requirement_assignment_relationship(context, our_relationship, + relationship_property_definitions, + relationship_interface_definitions, + requirement, our_relationship) + + +def merge_requirement_assignment_relationship(context, presentation, property_definitions, + interface_definitions, requirement, our_relationship): + our_relationship_properties = our_relationship._raw.get('properties') + if our_relationship_properties: + # Make sure we have a dict + if 'properties' not in requirement._raw['relationship']: + requirement._raw['relationship']['properties'] = OrderedDict() + + # Merge our properties + for property_name, prop in our_relationship_properties.iteritems(): + if property_name in property_definitions: + definition = property_definitions[property_name] + requirement._raw['relationship']['properties'][property_name] = \ + coerce_parameter_value(context, presentation, definition, prop) + else: + context.validation.report( + 'relationship property "%s" not declared at definition of requirement "%s"' + ' in "%s"' + % (property_name, requirement._fullname, + presentation._container._container._fullname), + locator=our_relationship._get_child_locator('properties', property_name), + level=Issue.BETWEEN_TYPES) + + our_interfaces = our_relationship.interfaces + if our_interfaces: + # Make sure we have a dict + if 'interfaces' not in requirement._raw['relationship']: + requirement._raw['relationship']['interfaces'] = OrderedDict() + + # Merge interfaces + for interface_name, our_interface in our_interfaces.iteritems(): + if interface_name not in requirement._raw['relationship']['interfaces']: + requirement._raw['relationship']['interfaces'][interface_name] = OrderedDict() + + if (interface_definitions is not None) and (interface_name in interface_definitions): + interface_definition = interface_definitions[interface_name] + interface_assignment = requirement.relationship.interfaces[interface_name] + merge_interface(context, presentation, interface_assignment, our_interface, + interface_definition, interface_name) + else: + context.validation.report( + 'relationship interface "%s" not declared at definition of requirement "%s"' + ' in "%s"' + % (interface_name, requirement._fullname, + presentation._container._container._fullname), + locator=our_relationship._locator, level=Issue.BETWEEN_TYPES) + + +def validate_requirement_assignment(context, presentation, requirement_assignment, + relationship_property_definitions, + relationship_interface_definitions): + relationship = requirement_assignment.relationship + if relationship is None: + return + + validate_required_values(context, presentation, relationship.properties, + relationship_property_definitions) + + if relationship_interface_definitions: + for interface_name, relationship_interface_definition \ + in relationship_interface_definitions.iteritems(): + interface_assignment = relationship.interfaces.get(interface_name) \ + if relationship.interfaces is not None else None + validate_required_inputs(context, presentation, interface_assignment, + relationship_interface_definition, None, interface_name) + + +def get_first_requirement(requirement_definitions, name): + if requirement_definitions is not None: + for requirement_name, requirement_definition in requirement_definitions: + if requirement_name == name: + return requirement_definition + return None diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py new file mode 100644 index 0000000..e2af4b8 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py @@ -0,0 +1,167 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.formatting import safe_repr +from aria.parser.validation import Issue + + +def validate_substitution_mappings_requirement(context, presentation): + + # validate that the requirement in substitution_mapping is defined in the substitution node type + substitution_node_type = presentation._container._get_type(context) + if substitution_node_type is None: + return + for req_name, req in substitution_node_type._get_requirements(context): + if req_name == presentation._name: + substitution_type_requirement = req + break + else: + context.validation.report( + 'substitution mapping requirement "{0}" is not declared in node type "{1}"'.format( + presentation._name, substitution_node_type._name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + return + + if not _validate_mapping_format(presentation): + _report_invalid_mapping_format(context, presentation, field='requirement') + return + + # validate that the mapped requirement is defined in the corresponding node template + node_template = _get_node_template(context, presentation) + if node_template is None: + _report_missing_node_template(context, presentation, field='requirement') + return + mapped_requirement_name = presentation._raw[1] + for req_name, req in node_template._get_requirements(context): + if req_name == mapped_requirement_name: + node_template_requirement = req + break + else: + context.validation.report( + 'substitution mapping requirement "{0}" refers to an unknown requirement of node ' + 'template "{1}": {mapped_requirement_name}'.format( + presentation._name, node_template._name, + mapped_requirement_name=safe_repr(mapped_requirement_name)), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + return + + # validate that the requirement's capability type in substitution_mapping is derived from the + # requirement's capability type in the corresponding node template + substitution_type_requirement_capability_type = \ + substitution_type_requirement._get_capability_type(context) + node_template_requirement_capability_type = \ + node_template_requirement._get_capability(context)[0] + if not node_template_requirement_capability_type._is_descendant( + context, substitution_type_requirement_capability_type): + context.validation.report( + 'substitution mapping requirement "{0}" of capability type "{1}" is not a descendant ' + 'of the mapped node template capability type "{2}"'.format( + presentation._name, + substitution_type_requirement_capability_type._name, + node_template_requirement_capability_type._name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + +def validate_substitution_mappings_capability(context, presentation): + + # validate that the capability in substitution_mapping is defined in the substitution node type + substitution_node_type = presentation._container._get_type(context) + if substitution_node_type is None: + return + substitution_type_capabilities = substitution_node_type._get_capabilities(context) + substitution_type_capability = substitution_type_capabilities.get(presentation._name) + if substitution_type_capability is None: + context.validation.report( + 'substitution mapping capability "{0}" ' + 'is not declared in node type "{substitution_type}"'.format( + presentation._name, substitution_type=substitution_node_type._name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + return + + if not _validate_mapping_format(presentation): + _report_invalid_mapping_format(context, presentation, field='capability') + return + + # validate that the capability in substitution_mapping is declared in the corresponding + # node template + node_template = _get_node_template(context, presentation) + if node_template is None: + _report_missing_node_template(context, presentation, field='capability') + return + mapped_capability_name = presentation._raw[1] + node_template_capability = node_template._get_capabilities(context).get(mapped_capability_name) + + if node_template_capability is None: + context.validation.report( + 'substitution mapping capability "{0}" refers to an unknown ' + 'capability of node template "{1}": {mapped_capability_name}'.format( + presentation._name, node_template._name, + mapped_capability_name=safe_repr(mapped_capability_name)), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + return + + # validate that the capability type in substitution_mapping is derived from the capability type + # in the corresponding node template + substitution_type_capability_type = substitution_type_capability._get_type(context) + node_template_capability_type = node_template_capability._get_type(context) + + if not substitution_type_capability_type._is_descendant(context, node_template_capability_type): + context.validation.report( + 'node template capability type "{0}" is not a descendant of substitution mapping ' + 'capability "{1}" of type "{2}"'.format( + node_template_capability_type._name, + presentation._name, + substitution_type_capability_type._name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + +# +# Utils +# + +def _validate_mapping_format(presentation): + """Validate that the mapping is a list of 2 strings""" + if not isinstance(presentation._raw, list) or \ + len(presentation._raw) != 2 or \ + not isinstance(presentation._raw[0], basestring) or \ + not isinstance(presentation._raw[1], basestring): + return False + return True + + +def _get_node_template(context, presentation): + node_template_name = presentation._raw[0] + node_template = context.presentation.get_from_dict('service_template', 'topology_template', + 'node_templates', node_template_name) + return node_template + + +def _report_missing_node_template(context, presentation, field): + context.validation.report( + 'substitution mappings {field} "{node_template_mapping}" ' + 'refers to an unknown node template: {node_template_name}'.format( + field=field, + node_template_mapping=presentation._name, + node_template_name=safe_repr(presentation._raw[0])), + locator=presentation._locator, level=Issue.FIELD) + + +def _report_invalid_mapping_format(context, presentation, field): + context.validation.report( + 'substitution mapping {field} "{field_name}" is not a list of 2 strings: {value}'.format( + field=field, + field_name=presentation._name, + value=safe_repr(presentation._raw)), + locator=presentation._locator, level=Issue.FIELD) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/__init__.py new file mode 100644 index 0000000..ae1e83e --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/__init__.py @@ -0,0 +1,14 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py new file mode 100644 index 0000000..0e3c94d --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py @@ -0,0 +1,33 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.caching import cachedmethod +from aria.parser.presentation import (Presentation, has_fields, primitive_dict_field) + + +@has_fields +class ExtensiblePresentation(Presentation): + """ + A presentation that supports an optional ``_extensions`` dict field. + """ + + @primitive_dict_field() + def _extensions(self): + pass + + @cachedmethod + def _get_extension(self, name, default=None): + extensions = self._extensions + return extensions.get(name, default) if extensions is not None else None # pylint: disable=no-member diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py new file mode 100644 index 0000000..f14164a --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py @@ -0,0 +1,37 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.formatting import safe_repr +from aria.parser.exceptions import InvalidValueError + + +def data_type_class_getter(cls): + """ + Wraps the field value in a specialized data type class. + + Can be used with the :func:`field_getter` decorator. + """ + + def getter(field, presentation, context=None): + raw = field.default_get(presentation, context) + if raw is not None: + try: + return cls(None, None, raw, None) + except ValueError as e: + raise InvalidValueError( + '%s is not a valid "%s" in "%s": %s' + % (field.full_name, field.full_cls_name, presentation._name, safe_repr(raw)), + cause=e, locator=field.get_locator(raw)) + return getter diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py new file mode 100644 index 0000000..e5853d8 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py @@ -0,0 +1,588 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re + +from aria.utils.formatting import safe_repr +from aria.parser import implements_specification +from aria.parser.presentation import (report_issue_for_unknown_type, derived_from_validator) +from aria.parser.validation import Issue + +from ..modeling.data_types import (get_primitive_data_type, get_data_type_name, coerce_value, + get_container_data_type) +from .types import (get_type_by_name, convert_name_to_full_type_name) + + + +# +# NodeTemplate, RelationshipTemplate +# + +@implements_specification('3.7.3.3', 'tosca-simple-1.0') +def copy_validator(template_type_name, templates_dict_name): + """ + Makes sure that the field refers to an existing template defined in the root presenter. + + Use with the :func:`field_validator` decorator for the ``copy`` field in + :class:`NodeTemplate` and :class:`RelationshipTemplate`. + """ + + def validator_fn(field, presentation, context): + field.default_validate(presentation, context) + + # Make sure type exists + value = getattr(presentation, field.name) + if value is not None: + copy = context.presentation.get_from_dict('service_template', 'topology_template', + templates_dict_name, value) + if copy is None: + report_issue_for_unknown_type(context, presentation, template_type_name, field.name) + else: + if copy.copy is not None: + context.validation.report( + '"copy" field refers to a %s that itself is a copy in "%s": %s' + % (template_type_name, presentation._fullname, safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + return validator_fn + + +# +# PropertyDefinition, AttributeDefinition, ParameterDefinition, EntrySchema +# + +def data_type_validator(type_name='data type'): + """ + Makes sure that the field refers to a valid data type, whether complex or primitive. + + Used with the :func:`field_validator` decorator for the ``type`` fields in + :class:`PropertyDefinition`, :class:`AttributeDefinition`, :class:`ParameterDefinition`, + and :class:`EntrySchema`. + + Extra behavior beyond validation: generated function returns true if field is a complex data + type. + """ + + def validator(field, presentation, context): + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + # Test for circular definitions + container_data_type = get_container_data_type(presentation) + if (container_data_type is not None) and (container_data_type._name == value): + context.validation.report( + 'type of property "%s" creates a circular value hierarchy: %s' + % (presentation._fullname, safe_repr(value)), + locator=presentation._get_child_locator('type'), level=Issue.BETWEEN_TYPES) + + # Can be a complex data type + if get_type_by_name(context, value, 'data_types') is not None: + return True + + # Can be a primitive data type + if get_primitive_data_type(value) is None: + report_issue_for_unknown_type(context, presentation, type_name, field.name) + + return False + + return validator + + +# +# PropertyDefinition, AttributeDefinition +# + +def entry_schema_validator(field, presentation, context): + """ + According to whether the data type supports ``entry_schema`` (e.g., it is or inherits from + list or map), make sure that we either have or don't have a valid data type value. + + Used with the :func:`field_validator` decorator for the ``entry_schema`` field in + :class:`PropertyDefinition` and :class:`AttributeDefinition`. + """ + + field.default_validate(presentation, context) + + def type_uses_entry_schema(the_type): + use_entry_schema = the_type._get_extension('use_entry_schema', False) \ + if hasattr(the_type, '_get_extension') else False + if use_entry_schema: + return True + parent = the_type._get_parent(context) if hasattr(the_type, '_get_parent') else None + if parent is None: + return False + return type_uses_entry_schema(parent) + + value = getattr(presentation, field.name) + the_type = presentation._get_type(context) + if the_type is None: + return + use_entry_schema = type_uses_entry_schema(the_type) + + if use_entry_schema: + if value is None: + context.validation.report( + '"entry_schema" does not have a value as required by data type "%s" in "%s"' + % (get_data_type_name(the_type), presentation._container._fullname), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + else: + if value is not None: + context.validation.report( + '"entry_schema" has a value but it is not used by data type "%s" in "%s"' + % (get_data_type_name(the_type), presentation._container._fullname), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + +def data_value_validator(field, presentation, context): + """ + Makes sure that the field contains a valid value according to data type and constraints. + + Used with the :func:`field_validator` decorator for the ``default`` field in + :class:`PropertyDefinition` and :class:`AttributeDefinition`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + the_type = presentation._get_type(context) + entry_schema = presentation.entry_schema + # AttributeDefinition does not have this: + constraints = presentation._get_constraints(context) \ + if hasattr(presentation, '_get_constraints') else None + coerce_value(context, presentation, the_type, entry_schema, constraints, value, field.name) + + +# +# DataType +# + +_data_type_validator = data_type_validator() +_data_type_derived_from_validator = derived_from_validator(convert_name_to_full_type_name, + 'data_types') + + +def data_type_derived_from_validator(field, presentation, context): + """ + Makes sure that the field refers to a valid parent data type (complex or primitive). + + Used with the :func:`field_validator` decorator for the ``derived_from`` field in + :class:`DataType`. + """ + + if _data_type_validator(field, presentation, context): + # Validate derivation only if a complex data type (primitive types have no derivation + # hierarchy) + _data_type_derived_from_validator(field, presentation, context) + + +def data_type_constraints_validator(field, presentation, context): + """ + Makes sure that we do not have constraints if we are a complex type (with no primitive + ancestor). + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + if presentation._get_primitive_ancestor(context) is None: + context.validation.report( + 'data type "%s" defines constraints but does not have a primitive ancestor' + % presentation._fullname, + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + + +def data_type_properties_validator(field, presentation, context): + """ + Makes sure that we do not have properties if we have a primitive ancestor. + + Used with the :func:`field_validator` decorator for the ``properties`` field in + :class:`DataType`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + if presentation._get_primitive_ancestor(context) is not None: + context.validation.report( + 'data type "%s" defines properties even though it has a primitive ancestor' + % presentation._fullname, + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + + +# +# ConstraintClause +# + +def constraint_clause_field_validator(field, presentation, context): + """ + Makes sure that field contains a valid value for the container type. + + Used with the :func:`field_validator` decorator for various field in :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + the_type = presentation._get_type(context) + constraints = the_type._get_constraints(context) \ + if hasattr(the_type, '_get_constraints') else None + coerce_value(context, presentation, the_type, None, constraints, value, field.name) + + +def constraint_clause_in_range_validator(field, presentation, context): + """ + Makes sure that the value is a list with exactly two elements, that both lower bound contains a + valid value for the container type, and that the upper bound is either "UNBOUNDED" or a valid + value for the container type. + + Used with the :func:`field_validator` decorator for the ``in_range`` field in + :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if isinstance(values, list): + # Make sure list has exactly two elements + if len(values) == 2: + lower, upper = values + the_type = presentation._get_type(context) + + # Lower bound must be coercible + lower = coerce_value(context, presentation, the_type, None, None, lower, field.name) + + if upper != 'UNBOUNDED': + # Upper bound be coercible + upper = coerce_value(context, presentation, the_type, None, None, upper, field.name) + + # Second "in_range" value must be greater than first + if (lower is not None) and (upper is not None) and (lower >= upper): + context.validation.report( + 'upper bound of "in_range" constraint is not greater than the lower bound' + ' in "%s": %s <= %s' + % (presentation._container._fullname, safe_repr(lower), safe_repr(upper)), + locator=presentation._locator, level=Issue.FIELD) + else: + context.validation.report( + 'constraint "%s" is not a list of exactly 2 elements in "%s"' + % (field.name, presentation._fullname), + locator=presentation._get_child_locator(field.name), level=Issue.FIELD) + + +def constraint_clause_valid_values_validator(field, presentation, context): + """ + Makes sure that the value is a list of valid values for the container type. + + Used with the :func:`field_validator` decorator for the ``valid_values`` field in + :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if isinstance(values, list): + the_type = presentation._get_type(context) + for value in values: + coerce_value(context, presentation, the_type, None, None, value, field.name) + + +def constraint_clause_pattern_validator(field, presentation, context): + """ + Makes sure that the value is a valid regular expression. + + Used with the :func:`field_validator` decorator for the ``pattern`` field in + :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + try: + # From TOSCA 1.0 3.5.2.1: + # + # "Note: Future drafts of this specification will detail the use of regular expressions + # and reference an appropriate standardized grammar." + # + # So we will just use Python's. + re.compile(value) + except re.error as e: + context.validation.report( + 'constraint "%s" is not a valid regular expression in "%s"' + % (field.name, presentation._fullname), + locator=presentation._get_child_locator(field.name), level=Issue.FIELD, exception=e) + + +# +# RequirementAssignment +# + +def node_template_or_type_validator(field, presentation, context): + """ + Makes sure that the field refers to either a node template or a node type. + + Used with the :func:`field_validator` decorator for the ``node`` field in + :class:`RequirementAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + node_templates = \ + context.presentation.get('service_template', 'topology_template', 'node_templates') \ + or {} + if (value not in node_templates) and \ + (get_type_by_name(context, value, 'node_types') is None): + report_issue_for_unknown_type(context, presentation, 'node template or node type', + field.name) + + +def capability_definition_or_type_validator(field, presentation, context): + """ + Makes sure refers to either a capability assignment name in the node template referred to by the + ``node`` field or a general capability type. + + If the value refers to a capability type, make sure the ``node`` field was not assigned. + + Used with the :func:`field_validator` decorator for the ``capability`` field in + :class:`RequirementAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + node, node_variant = presentation._get_node(context) + if node_variant == 'node_template': + capabilities = node._get_capabilities(context) + if value in capabilities: + return + + if get_type_by_name(context, value, 'capability_types') is not None: + if node is not None: + context.validation.report( + '"%s" refers to a capability type even though "node" has a value in "%s"' + % (presentation._name, presentation._container._fullname), + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_FIELDS) + return + + if node_variant == 'node_template': + context.validation.report( + 'requirement "%s" refers to an unknown capability definition name or capability' + ' type in "%s": %s' + % (presentation._name, presentation._container._fullname, safe_repr(value)), + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'requirement "%s" refers to an unknown capability type in "%s": %s' + % (presentation._name, presentation._container._fullname, safe_repr(value)), + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + + +def node_filter_validator(field, presentation, context): + """ + Makes sure that the field has a value only if "node" refers to a node type. + + Used with the :func:`field_validator` decorator for the ``node_filter`` field in + :class:`RequirementAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + _, node_type_variant = presentation._get_node(context) + if node_type_variant != 'node_type': + context.validation.report( + 'requirement "%s" has a node filter even though "node" does not refer to a node' + ' type in "%s"' + % (presentation._fullname, presentation._container._fullname), + locator=presentation._locator, level=Issue.BETWEEN_FIELDS) + + +# +# RelationshipAssignment +# + +def relationship_template_or_type_validator(field, presentation, context): + """ + Makes sure that the field refers to either a relationship template or a relationship type. + + Used with the :func:`field_validator` decorator for the ``type`` field in + :class:`RelationshipAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + relationship_templates = \ + context.presentation.get('service_template', 'topology_template', + 'relationship_templates') \ + or {} + if (value not in relationship_templates) and \ + (get_type_by_name(context, value, 'relationship_types') is None): + report_issue_for_unknown_type(context, presentation, + 'relationship template or relationship type', field.name) + + +# +# PolicyType +# + +def list_node_type_or_group_type_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to either node types or a group types. + + Used with the :func:`field_validator` decorator for the ``targets`` field in + :class:`PolicyType`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + for value in values: + if (get_type_by_name(context, value, 'node_types') is None) and \ + (get_type_by_name(context, value, 'group_types') is None): + report_issue_for_unknown_type(context, presentation, 'node type or group type', + field.name, value) + + +# +# PolicyTemplate +# + +def policy_targets_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to either node templates or groups, and that + they match the node types and group types declared in the policy type. + + Used with the :func:`field_validator` decorator for the ``targets`` field in + :class:`PolicyTemplate`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + for value in values: + node_templates = \ + context.presentation.get('service_template', 'topology_template', + 'node_templates') \ + or {} + groups = context.presentation.get('service_template', 'topology_template', 'groups') \ + or {} + if (value not in node_templates) and (value not in groups): + report_issue_for_unknown_type(context, presentation, 'node template or group', + field.name, value) + + policy_type = presentation._get_type(context) + if policy_type is None: + break + + node_types, group_types = policy_type._get_targets(context) + + is_valid = False + + if value in node_templates: + our_node_type = node_templates[value]._get_type(context) + for node_type in node_types: + if node_type._is_descendant(context, our_node_type): + is_valid = True + break + + elif value in groups: + our_group_type = groups[value]._get_type(context) + for group_type in group_types: + if group_type._is_descendant(context, our_group_type): + is_valid = True + break + + if not is_valid: + context.validation.report( + 'policy definition target does not match either a node type or a group type' + ' declared in the policy type in "%s": %s' + % (presentation._name, safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + +# +# NodeFilter +# + +def node_filter_properties_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to defined properties in the target node type. + + Used with the :func:`field_validator` decorator for the ``properties`` field in + :class:`NodeFilter`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + node_type = presentation._get_node_type(context) + if node_type is not None: + properties = node_type._get_properties(context) + for name, _ in values: + if name not in properties: + context.validation.report( + 'node filter refers to an unknown property definition in "%s": %s' + % (node_type._name, name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + +def node_filter_capabilities_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to defined capabilities and properties in the target + node type. + + Used with the :func:`field_validator` decorator for the ``capabilities`` field in + :class:`NodeFilter`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: # pylint: disable=too-many-nested-blocks + node_type = presentation._get_node_type(context) + if node_type is not None: + capabilities = node_type._get_capabilities(context) + for name, value in values: + capability = capabilities.get(name) + if capability is not None: + properties = value.properties + capability_properties = capability.properties + if (properties is not None) and (capability_properties is not None): + for property_name, _ in properties: + if property_name not in capability_properties: + context.validation.report( + 'node filter refers to an unknown capability definition' + ' property in "%s": %s' + % (node_type._name, property_name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'node filter refers to an unknown capability definition in "%s": %s' + % (node_type._name, name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py new file mode 100644 index 0000000..5f9750e --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py @@ -0,0 +1,63 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def convert_name_to_full_type_name(context, name, types_dict): # pylint: disable=unused-argument + """ + Converts a type name to its full type name, or else returns it unchanged. + + Works by checking for ``shorthand_name`` and ``type_qualified_name`` in the types' + ``_extensions`` field. See also + :class:`aria_extension_tosca.v1_0.presentation.extensible.ExtensiblePresentation`. + + Can be used as the conversion function argument in ``type_validator`` and + ``derived_from_validator``. + """ + + if (name is not None) and types_dict and (name not in types_dict): + for full_name, the_type in types_dict.iteritems(): + if hasattr(the_type, '_extensions') and the_type._extensions \ + and ((the_type._extensions.get('shorthand_name') == name) \ + or (the_type._extensions.get('type_qualified_name') == name)): + return full_name + return name + + +def get_type_by_name(context, name, *types_dict_names): + """ + Gets a type either by its full name or its shorthand name or type-qualified name. + + Works by checking for ``shorthand_name`` and ``type_qualified_name`` in the types' + ``_extensions`` field. See also + :class:`~aria_extension_tosca.v1_0.presentation.extensible.ExtensiblePresentation`. + + The arguments from the third onwards are used to locate a nested field under + ``service_template`` under the root presenter. + """ + + if name is not None: + types_dict = context.presentation.get('service_template', *types_dict_names) + if types_dict: + the_type = types_dict.get(name) + if the_type is not None: + # Full name + return the_type + for the_type in types_dict.itervalues(): + if hasattr(the_type, '_extensions') and the_type._extensions \ + and ((the_type._extensions.get('shorthand_name') == name) \ + or (the_type._extensions.get('type_qualified_name') == name)): + # Shorthand name + return the_type + return None diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presenter.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presenter.py new file mode 100644 index 0000000..8e1809f --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/presenter.py @@ -0,0 +1,83 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import (FrozenList, EMPTY_READ_ONLY_LIST) +from aria.utils.caching import cachedmethod +from aria.parser.presentation import Presenter + +from .modeling import create_service_template_model +from .modeling.functions import (Concat, Token, GetInput, GetProperty, GetAttribute, + GetOperationOutput, GetNodesOfType, GetArtifact) +from .templates import ServiceTemplate + + +class ToscaSimplePresenter1_0(Presenter): # pylint: disable=invalid-name,abstract-method + """ + ARIA presenter for the `TOSCA Simple Profile v1.0 cos01 <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html>`__. + + Supported ``tosca_definitions_version`` values: + + * ``tosca_simple_yaml_1_0`` + """ + + DSL_VERSIONS = ('tosca_simple_yaml_1_0',) + ALLOWED_IMPORTED_DSL_VERSIONS = ('tosca_simple_yaml_1_0',) + SIMPLE_PROFILE_LOCATION = 'tosca-simple-1.0/tosca-simple-1.0.yaml' + SPECIAL_IMPORTS = { + 'aria-1.0': 'aria-1.0/aria-1.0.yaml', + 'azure-plugin':'azure-plugin/azureplugin.yaml'} + + @property + @cachedmethod + def service_template(self): + return ServiceTemplate(raw=self._raw) + + @property + @cachedmethod + def functions(self): + return { + 'concat': Concat, + 'token': Token, + 'get_input': GetInput, + 'get_property': GetProperty, + 'get_attribute': GetAttribute, + 'get_operation_output': GetOperationOutput, + 'get_nodes_of_type': GetNodesOfType, + 'get_artifact': GetArtifact} + + # Presentation + + def _dump(self, context): + self.service_template._dump(context) + + def _validate(self, context): + self.service_template._validate(context) + + # Presenter + + @cachedmethod + def _get_import_locations(self, context): + import_locations = [] + if context.presentation.import_profile: + import_locations.append(self.SIMPLE_PROFILE_LOCATION) + imports = self._get('service_template', 'imports') + if imports: + import_locations += [self.SPECIAL_IMPORTS.get(i.file, i.file) for i in imports] + return FrozenList(import_locations) if import_locations else EMPTY_READ_ONLY_LIST + + @cachedmethod + def _get_model(self, context): # pylint: disable=no-self-use + return create_service_template_model(context) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/templates.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/templates.py new file mode 100644 index 0000000..3c36bb8 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/templates.py @@ -0,0 +1,736 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import (FrozenDict, FrozenList) +from aria.utils.caching import cachedmethod +from aria.parser import implements_specification +from aria.parser.presentation import (has_fields, primitive_field, primitive_list_field, + object_field, object_list_field, object_dict_field, + object_sequenced_list_field, field_validator, + type_validator, list_type_validator) + +from .assignments import (PropertyAssignment, AttributeAssignment, RequirementAssignment, + CapabilityAssignment, InterfaceAssignment, ArtifactAssignment) +from .definitions import ParameterDefinition +from .filters import NodeFilter +from .misc import (Description, MetaData, Repository, Import, SubstitutionMappings) +from .modeling.parameters import (get_assigned_and_defined_parameter_values, get_parameter_values) +from .modeling.interfaces import get_template_interfaces +from .modeling.requirements import get_template_requirements +from .modeling.capabilities import get_template_capabilities +from .modeling.artifacts import get_inherited_artifact_definitions +from .modeling.policies import get_policy_targets +from .modeling.copy import get_default_raw_from_copy +from .presentation.extensible import ExtensiblePresentation +from .presentation.field_validators import copy_validator, policy_targets_validator +from .presentation.types import (convert_name_to_full_type_name, get_type_by_name) +from .types import (ArtifactType, DataType, CapabilityType, InterfaceType, RelationshipType, + NodeType, GroupType, PolicyType) + + +@has_fields +@implements_specification('3.7.3', 'tosca-simple-1.0') +class NodeTemplate(ExtensiblePresentation): + """ + A Node Template specifies the occurrence of a manageable software component as part of an + application's topology model which is defined in a TOSCA Service Template. A Node template is an + instance of a specified Node Type and can provide customized properties, constraints or + operations which override the defaults provided by its Node Type and its implementations. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_NODE_TEMPLATE>`__ + """ + + @field_validator(type_validator('node type', convert_name_to_full_type_name, 'node_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the Node Type the Node Template is based upon. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Node Template. + + :type: :class:`Description` + """ + + @primitive_list_field(str) + def directives(self): + """ + An optional list of directive values to provide processing instructions to orchestrators and + tooling. + + :type: [:obj:`basestring`] + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property value assignments for the Node Template. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @object_dict_field(AttributeAssignment) + def attributes(self): + """ + An optional list of attribute value assignments for the Node Template. + + :type: {:obj:`basestring`: :class:`AttributeAssignment`} + """ + + @object_sequenced_list_field(RequirementAssignment) + def requirements(self): + """ + An optional sequenced list of requirement assignments for the Node Template. + + :type: list of (str, :class:`RequirementAssignment`) + """ + + @object_dict_field(CapabilityAssignment) + def capabilities(self): + """ + An optional list of capability assignments for the Node Template. + + :type: {:obj:`basestring`: :class:`CapabilityAssignment`} + """ + + @object_dict_field(InterfaceAssignment) + def interfaces(self): + """ + An optional list of named interface definitions for the Node Template. + + :type: {:obj:`basestring`: :class:`InterfaceAssignment`} + """ + + @object_dict_field(ArtifactAssignment) + def artifacts(self): + """ + An optional list of named artifact definitions for the Node Template. + + :type: {:obj:`basestring`: :class:`ArtifactAssignment`} + """ + + @object_field(NodeFilter) + def node_filter(self): + """ + The optional filter definition that TOSCA orchestrators would use to select the correct + target node. This keyname is only valid if the directive has the value of "selectable" set. + + :type: :class:`NodeFilter` + """ + + @field_validator(copy_validator('node template', 'node_templates')) + @primitive_field(str) + def copy(self): + """ + The optional (symbolic) name of another node template to copy into (all keynames and values) + and use as a basis for this node template. + + :type: :obj:`basestring` + """ + + @cachedmethod + def _get_default_raw(self): + return get_default_raw_from_copy(self, 'node_templates') + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'node_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_parameter_values(context, self, 'property')) + + @cachedmethod + def _get_attribute_default_values(self, context): + return FrozenDict(get_assigned_and_defined_parameter_values(context, self, 'attribute')) + + @cachedmethod + def _get_requirements(self, context): + return FrozenList(get_template_requirements(context, self)) + + @cachedmethod + def _get_capabilities(self, context): + return FrozenDict(get_template_capabilities(context, self)) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_template_interfaces(context, self, 'node template')) + + @cachedmethod + def _get_artifacts(self, context): + return FrozenDict(get_inherited_artifact_definitions(context, self)) + + def _validate(self, context): + super(NodeTemplate, self)._validate(context) + self._get_property_values(context) + self._get_requirements(context) + self._get_capabilities(context) + self._get_interfaces(context) + self._get_artifacts(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'type', + 'directives', + 'properties', + 'attributes', + 'requirements', + 'capabilities', + 'interfaces', + 'artifacts', + 'node_filter', + 'copy')) + + +@has_fields +@implements_specification('3.7.4', 'tosca-simple-1.0') +class RelationshipTemplate(ExtensiblePresentation): + """ + A Relationship Template specifies the occurrence of a manageable relationship between node + templates as part of an application's topology model that is defined in a TOSCA Service + Template. A Relationship template is an instance of a specified Relationship Type and can + provide customized properties, constraints or operations which override the defaults provided by + its Relationship Type and its implementations. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_RELATIONSHIP_TEMPLATE>`__ + """ + + @field_validator(type_validator('relationship type', convert_name_to_full_type_name, + 'relationship_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the Relationship Type the Relationship Template is based upon. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Relationship Template. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property assignments for the Relationship Template. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @object_dict_field(AttributeAssignment) + def attributes(self): + """ + An optional list of attribute assignments for the Relationship Template. + + :type: {:obj:`basestring`: :class:`AttributeAssignment`} + """ + + @object_dict_field(InterfaceAssignment) + def interfaces(self): + """ + An optional list of named interface definitions for the Node Template. + + ARIA NOTE: Spec is wrong here, should be Relationship Template. + + :type: {:obj:`basestring`: :class:`InterfaceAssignment`} + """ + + @field_validator(copy_validator('relationship template', 'relationship_templates')) + @primitive_field(str) + def copy(self): + """ + The optional (symbolic) name of another relationship template to copy into (all keynames and + values) and use as a basis for this relationship template. + + :type: :obj:`basestring` + """ + + @cachedmethod + def _get_default_raw(self): + return get_default_raw_from_copy(self, 'relationship_templates') + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'relationship_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_parameter_values(context, self, 'property')) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_template_interfaces(context, self, 'relationship template')) + + def _validate(self, context): + super(RelationshipTemplate, self)._validate(context) + self._get_property_values(context) + self._get_interfaces(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'type', + 'properties', + 'attributes', + 'interfaces', + 'copy')) + + +@has_fields +@implements_specification('3.7.5', 'tosca-simple-1.0') +class GroupTemplate(ExtensiblePresentation): + """ + A group definition defines a logical grouping of node templates, typically for management + purposes, but is separate from the application's topology template. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_GROUP_DEF>`__ + """ + + @field_validator(type_validator('group type', convert_name_to_full_type_name, + 'group_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the group type the group definition is based upon. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the group definition. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property value assignments for the group definition. + + :type: {:obj:`basestring`: :class:`PropertyAssignment`} + """ + + @field_validator(list_type_validator('node template', 'topology_template', 'node_templates')) + @primitive_list_field(str) + def members(self): + """ + The optional list of one or more node template names that are members of this group + definition. + + :type: [:obj:`basestring`] + """ + + @object_dict_field(InterfaceAssignment) + def interfaces(self): + """ + An optional list of named interface definitions for the group definition. + + :type: {:obj:`basestring`: :class:`InterfaceDefinition`} + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'group_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_parameter_values(context, self, 'property')) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_template_interfaces(context, self, 'group definition')) + + def _validate(self, context): + super(GroupTemplate, self)._validate(context) + self._get_property_values(context) + self._get_interfaces(context) + + +@has_fields +@implements_specification('3.7.6', 'tosca-simple-1.0') +class PolicyTemplate(ExtensiblePresentation): + """ + A policy definition defines a policy that can be associated with a TOSCA topology or top-level + entity definition (e.g., group definition, node template, etc.). + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_POLICY_DEF>`__ + """ + + @field_validator(type_validator('policy type', convert_name_to_full_type_name, 'policy_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the policy type the policy definition is based upon. + + :type: :obj:`basestring` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the policy definition. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property value assignments for the policy definition. + + :type: {:obj:`basestring`: :class:`PropertyAssignment` + """ + + @field_validator(policy_targets_validator) + @primitive_list_field(str) + def targets(self): + """ + An optional list of valid Node Templates or Groups the Policy can be applied to. + + :type: [:obj:`basestring`] + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_name(context, self.type, 'policy_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_parameter_values(context, self, 'property')) + + @cachedmethod + def _get_targets(self, context): + node_templates, groups = get_policy_targets(context, self) + return FrozenList(node_templates), FrozenList(groups) + + def _validate(self, context): + super(PolicyTemplate, self)._validate(context) + self._get_property_values(context) + + +@has_fields +@implements_specification('3.8', 'tosca-simple-1.0') +class TopologyTemplate(ExtensiblePresentation): + """ + This section defines the topology template of a cloud application. The main ingredients of the + topology template are node templates representing components of the application and relationship + templates representing links between the components. These elements are defined in the nested + ``node_templates`` section and the nested relationship_templates sections, respectively. + Furthermore, a topology template allows for defining input parameters, output parameters as well + as grouping of node templates. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_TOPOLOGY_TEMPLATE>`__ + """ + + @object_field(Description) + def description(self): + """ + The optional description for the Topology Template. + + :type: :class:`Description` + """ + + @object_dict_field(ParameterDefinition) + def inputs(self): + """ + An optional list of input parameters (i.e., as parameter definitions) for the Topology + Template. + + :type: {:obj:`basestring`: :class:`ParameterDefinition`} + """ + + @object_dict_field(NodeTemplate) + def node_templates(self): + """ + An optional list of node template definitions for the Topology Template. + + :type: {:obj:`basestring`: :class:`NodeTemplate`} + """ + + @object_dict_field(RelationshipTemplate) + def relationship_templates(self): + """ + An optional list of relationship templates for the Topology Template. + + :type: {:obj:`basestring`: :class:`RelationshipTemplate`} + """ + + @object_dict_field(GroupTemplate) + def groups(self): + """ + An optional list of Group definitions whose members are node templates defined within this + same Topology Template. + + :class:`GroupTemplate` + """ + + @object_dict_field(PolicyTemplate) + def policies(self): + """ + An optional list of Policy definitions for the Topology Template. + + :type: {:obj:`basestring`: :class:`PolicyTemplate`} + """ + + @object_dict_field(ParameterDefinition) + def outputs(self): + """ + An optional list of output parameters (i.e., as parameter definitions) for the Topology + Template. + + :type: {:obj:`basestring`: :class:`ParameterDefinition`} + """ + + @object_field(SubstitutionMappings) + def substitution_mappings(self): + """ + An optional declaration that exports the topology template as an implementation of a Node + type. + + This also includes the mappings between the external Node Types named capabilities and + requirements to existing implementations of those capabilities and requirements on Node + templates declared within the topology template. + """ + + @cachedmethod + def _get_input_values(self, context): + return FrozenDict(get_parameter_values(context, self, 'inputs')) + + @cachedmethod + def _get_output_values(self, context): + return FrozenDict(get_parameter_values(context, self, 'outputs')) + + def _validate(self, context): + super(TopologyTemplate, self)._validate(context) + self._get_input_values(context) + self._get_output_values(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'inputs', + 'node_templates', + 'relationship_templates', + 'groups', + 'policies', + 'outputs', + 'substitution_mappings')) + + +@has_fields +@implements_specification('3.9', 'tosca-simple-1.0') +class ServiceTemplate(ExtensiblePresentation): + """ + Servicate template. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ELEMENT_SERVICE_TEMPLATE>`__. + """ + + @primitive_field(str) + @implements_specification('3.9.3.1', 'tosca-simple-1.0') + def tosca_definitions_version(self): + """ + Defines the version of the TOSCA Simple Profile specification the template (grammar) + complies with. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #_Toc379455047>`__ + + :type: :obj:`basestring` + """ + + @object_field(MetaData) + def metadata(self): + """ + Defines a section used to declare additional metadata information. Domain-specific TOSCA + profile specifications may define keynames that are required for their implementations. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #_Toc379455048>`__ + + :type: :class:`MetaData` + """ + + @object_field(Description) + @implements_specification('3.9.3.6', 'tosca-simple-1.0') + def description(self): + """ + Declares a description for this Service Template and its contents. + + :type: :class:`Description` + """ + + @primitive_field() + @implements_specification('3.9.3.7', 'tosca-simple-1.0') + def dsl_definitions(self): + """ + Declares optional DSL-specific definitions and conventions. For example, in YAML, this + allows defining reusable YAML macros (i.e., YAML alias anchors) for use throughout the TOSCA + Service Template. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #_Toc397688790>`__ + """ + + @object_dict_field(Repository) + @implements_specification('3.9.3.8', 'tosca-simple-1.0') + def repositories(self): + """ + Declares the list of external repositories which contain artifacts that are referenced in + the service template along with their addresses and necessary credential information used to + connect to them in order to retrieve the artifacts. + + :type: {:obj:`basestring`: :class:`Repository`} + """ + + @object_list_field(Import) + @implements_specification('3.9.3.9', 'tosca-simple-1.0') + def imports(self): + """ + Declares import statements external TOSCA Definitions documents. For example, these may be + file location or URIs relative to the service template file within the same TOSCA CSAR file. + + :type: list of :class:`Import` + """ + + @object_dict_field(ArtifactType) + @implements_specification('3.9.3.10', 'tosca-simple-1.0') + def artifact_types(self): + """ + This section contains an optional list of artifact type definitions for use in the service + template. + + :type: {:obj:`basestring`: :class:`ArtifactType`} + """ + + @object_dict_field(DataType) + @implements_specification('3.9.3.11', 'tosca-simple-1.0') + def data_types(self): + """ + Declares a list of optional TOSCA Data Type definitions. + + :type: {:obj:`basestring`: :class:`DataType`} + """ + + @object_dict_field(CapabilityType) + @implements_specification('3.9.3.12', 'tosca-simple-1.0') + def capability_types(self): + """ + This section contains an optional list of capability type definitions for use in the service + template. + + :type: {:obj:`basestring`: :class:`CapabilityType`} + """ + + @object_dict_field(InterfaceType) + @implements_specification('3.9.3.13', 'tosca-simple-1.0') + def interface_types(self): + """ + This section contains an optional list of interface type definitions for use in the service + template. + + :type: {:obj:`basestring`: :class:`InterfaceType`} + """ + + @object_dict_field(RelationshipType) + @implements_specification('3.9.3.14', 'tosca-simple-1.0') + def relationship_types(self): + """ + This section contains a set of relationship type definitions for use in the service + template. + + :type: {:obj:`basestring`: :class:`RelationshipType`} + """ + + @object_dict_field(NodeType) + @implements_specification('3.9.3.15', 'tosca-simple-1.0') + def node_types(self): + """ + This section contains a set of node type definitions for use in the service template. + + :type: {:obj:`basestring`: :class:`NodeType`} + """ + + @object_dict_field(GroupType) + @implements_specification('3.9.3.16', 'tosca-simple-1.0') + def group_types(self): + """ + This section contains a list of group type definitions for use in the service template. + + :type: {:obj:`basestring`: :class:`GroupType`} + """ + + @object_dict_field(PolicyType) + @implements_specification('3.9.3.17', 'tosca-simple-1.0') + def policy_types(self): + """ + This section contains a list of policy type definitions for use in the service template. + + :type: {:obj:`basestring`: :class:`PolicyType`} + """ + + @object_field(TopologyTemplate) + def topology_template(self): + """ + Defines the topology template of an application or service, consisting of node templates + that represent the application's or service's components, as well as relationship templates + representing relations between the components. + + :type: :class:`TopologyTemplate` + """ + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'tosca_definitions_version', + 'metadata', + 'repositories', + 'imports', + 'artifact_types', + 'data_types', + 'capability_types', + 'interface_types', + 'relationship_types', + 'node_types', + 'group_types', + 'policy_types', + 'topology_template')) diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/types.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/types.py new file mode 100644 index 0000000..43af44b --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/types.py @@ -0,0 +1,892 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from aria.utils.collections import (FrozenDict, FrozenList) +from aria.utils.caching import cachedmethod +from aria.parser import implements_specification +from aria.parser.presentation import (has_fields, allow_unknown_fields, primitive_field, + primitive_list_field, object_field, object_dict_field, + object_list_field, object_sequenced_list_field, + object_dict_unknown_fields, field_getter, field_validator, + list_type_validator, derived_from_validator, + get_parent_presentation) + +from .assignments import ArtifactAssignmentForType +from .data_types import Version +from .definitions import (PropertyDefinition, AttributeDefinition, InterfaceDefinition, + RequirementDefinition, CapabilityDefinition, OperationDefinition) +from .misc import (Description, ConstraintClause) +from .modeling.artifacts import get_inherited_artifact_definitions +from .modeling.capabilities import (get_inherited_valid_source_types, + get_inherited_capability_definitions) +from .modeling.data_types import (get_data_type, get_inherited_constraints, coerce_data_type_value, + validate_data_type_name) +from .modeling.interfaces import (get_inherited_interface_definitions, get_inherited_operations) +from .modeling.policies import get_inherited_targets +from .modeling.parameters import get_inherited_parameter_definitions +from .modeling.requirements import get_inherited_requirement_definitions +from .presentation.extensible import ExtensiblePresentation +from .presentation.field_getters import data_type_class_getter +from .presentation.field_validators import (data_type_derived_from_validator, + data_type_constraints_validator, + data_type_properties_validator, + list_node_type_or_group_type_validator) +from .presentation.types import convert_name_to_full_type_name + + + +@has_fields +@implements_specification('3.6.3', 'tosca-simple-1.0') +class ArtifactType(ExtensiblePresentation): + """ + An Artifact Type is a reusable entity that defines the type of one or more files that are used + to define implementation or deployment artifacts that are referenced by nodes or relationships + on their operations. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_ARTIFACT_TYPE>`__ + """ + + @field_validator(derived_from_validator(convert_name_to_full_type_name, 'artifact_types')) + @primitive_field(str) + def derived_from(self): + """ + An optional parent Artifact Type name the Artifact Type derives from. + + :type: :obj:`basestring` + """ + + @field_getter(data_type_class_getter(Version)) + @primitive_field() + def version(self): + """ + An optional version for the Artifact Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Artifact Type. + + :type: :class:`Description` + """ + + @primitive_field(str) + def mime_type(self): + """ + The required mime type property for the Artifact Type. + + :type: :obj:`basestring` + """ + + @primitive_list_field(str) + def file_ext(self): + """ + The required file extension property for the Artifact Type. + + :type: [:obj:`basestring`] + """ + + @object_dict_field(PropertyDefinition) + def properties(self): + """ + An optional list of property definitions for the Artifact Type. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @cachedmethod + def _get_parent(self, context): + return get_parent_presentation(context, self, convert_name_to_full_type_name, + 'artifact_types') + + @cachedmethod + def _get_properties(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'properties')) + + def _validate(self, context): + super(ArtifactType, self)._validate(context) + self._get_properties(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'mime_type', + 'file_ext', + 'properties')) + + +@has_fields +@implements_specification('3.6.5', 'tosca-simple-1.0') +class DataType(ExtensiblePresentation): + """ + A Data Type definition defines the schema for new named datatypes in TOSCA. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_DATA_TYPE>`__ + """ + + @field_validator(data_type_derived_from_validator) + @primitive_field(str) + def derived_from(self): + """ + The optional key used when a datatype is derived from an existing TOSCA Data Type. + + :type: :obj:`basestring` + """ + + @object_field(Version) + def version(self): + """ + An optional version for the Data Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the Data Type. + + :type: :class:`Description` + """ + + @field_validator(data_type_constraints_validator) + @object_list_field(ConstraintClause) + def constraints(self): + """ + The optional list of sequenced constraint clauses for the Data Type. + + :type: list of (str, :class:`ConstraintClause`) + """ + + @field_validator(data_type_properties_validator) + @object_dict_field(PropertyDefinition) + def properties(self): + """ + The optional list property definitions that comprise the schema for a complex Data Type in + TOSCA. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @cachedmethod + def _get_parent(self, context): + return get_data_type(context, self, 'derived_from', allow_none=True) + + @cachedmethod + def _is_descendant(self, context, the_type): + if the_type is None: + return False + if not hasattr(the_type, '_name'): + # Must be a primitive type + return self._get_primitive_ancestor(context) == the_type + if the_type._name == self._name: + return True + return self._is_descendant(context, the_type._get_parent(context)) + + @cachedmethod + def _get_primitive_ancestor(self, context): + parent = self._get_parent(context) + if parent is not None: + if not isinstance(parent, DataType): + return parent + else: + return parent._get_primitive_ancestor(context) # pylint: disable=no-member + return None + + @cachedmethod + def _get_properties(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'properties')) + + @cachedmethod + def _get_constraints(self, context): + return get_inherited_constraints(context, self) + + def _validate(self, context): + super(DataType, self)._validate(context) + validate_data_type_name(context, self) + self._get_properties(context) + + def _coerce_value(self, context, presentation, entry_schema, constraints, value, aspect): + return coerce_data_type_value(context, presentation, self, entry_schema, constraints, value, + aspect) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'constraints', + 'properties')) + + +@has_fields +@implements_specification('3.6.6', 'tosca-simple-1.0') +class CapabilityType(ExtensiblePresentation): + """ + A Capability Type is a reusable entity that describes a kind of capability that a Node Type can + declare to expose. Requirements (implicit or explicit) that are declared as part of one node can + be matched to (i.e., fulfilled by) the Capabilities declared by another node. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_CAPABILITY_TYPE>`__ + """ + + @field_validator(derived_from_validator(convert_name_to_full_type_name, 'capability_types')) + @primitive_field(str) + def derived_from(self): + """ + An optional parent capability type name this new Capability Type derives from. + + :type: :obj:`basestring` + """ + + @object_field(Version) + def version(self): + """ + An optional version for the Capability Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Capability Type. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyDefinition) + def properties(self): + """ + An optional list of property definitions for the Capability Type. + + ARIA NOTE: The spec says 'list', but the examples are all of dicts. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @object_dict_field(AttributeDefinition) + def attributes(self): + """ + An optional list of attribute definitions for the Capability Type. + + :type: {:obj:`basestring`: :class:`AttributeDefinition`} + """ + + @field_validator(list_type_validator('node type', convert_name_to_full_type_name, 'node_types')) + @primitive_list_field(str) + def valid_source_types(self): + """ + An optional list of one or more valid names of Node Types that are supported as valid + sources of any relationship established to the declared Capability Type. + + :type: [:obj:`basestring`] + """ + + @cachedmethod + def _get_parent(self, context): + return get_parent_presentation(context, self, convert_name_to_full_type_name, + 'capability_types') + + @cachedmethod + def _is_descendant(self, context, other_type): + """returns True iff `other_type` is a descendant of the represented capability type""" + if other_type is None: + return False + elif other_type._name == self._name: + return True + return self._is_descendant(context, other_type._get_parent(context)) + + @cachedmethod + def _get_properties(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'properties')) + + @cachedmethod + def _get_valid_source_types(self, context): + return get_inherited_valid_source_types(context, self) + + def _validate(self, context): + super(CapabilityType, self)._validate(context) + self._get_properties(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'valid_source_types', + 'properties', + 'attributes')) + + +@allow_unknown_fields +@has_fields +@implements_specification('3.6.4', 'tosca-simple-1.0') +class InterfaceType(ExtensiblePresentation): + """ + An Interface Type is a reusable entity that describes a set of operations that can be used to + interact with or manage a node or relationship in a TOSCA topology. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_INTERFACE_TYPE>`__ + """ + + @field_validator(derived_from_validator(convert_name_to_full_type_name, 'interface_types')) + @primitive_field(str) + def derived_from(self): + """ + An optional parent Interface Type name this new Interface Type derives from. + + :type: :obj:`basestring` + """ + + @object_field(Version) + def version(self): + """ + An optional version for the Interface Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Interface Type. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyDefinition) + def inputs(self): + """ + The optional list of input parameter definitions. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @object_dict_unknown_fields(OperationDefinition) + def operations(self): + """ + :type: {:obj:`basestring`: :class:`OperationDefinition`} + """ + + @cachedmethod + def _get_parent(self, context): + return get_parent_presentation(context, self, convert_name_to_full_type_name, + 'interface_types') + + @cachedmethod + def _is_descendant(self, context, the_type): + if the_type is None: + return False + elif the_type._name == self._name: + return True + return self._is_descendant(context, the_type._get_parent(context)) + + @cachedmethod + def _get_inputs(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'inputs')) + + @cachedmethod + def _get_operations(self, context): + return FrozenDict(get_inherited_operations(context, self)) + + def _validate(self, context): + super(InterfaceType, self)._validate(context) + self._get_inputs(context) + for operation in self.operations.itervalues(): # pylint: disable=no-member + operation._validate(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'inputs', + 'operations')) + + +@has_fields +@implements_specification('3.6.9', 'tosca-simple-1.0') +class RelationshipType(ExtensiblePresentation): + """ + A Relationship Type is a reusable entity that defines the type of one or more relationships + between Node Types or Node Templates. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_RELATIONSHIP_TYPE>`__ + """ + + @field_validator(derived_from_validator(convert_name_to_full_type_name, 'relationship_types')) + @primitive_field(str) + def derived_from(self): + """ + An optional parent Relationship Type name the Relationship Type derives from. + + :type: :obj:`basestring` + """ + + @object_field(Version) + def version(self): + """ + An optional version for the Relationship Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Relationship Type. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyDefinition) + def properties(self): + """ + An optional list of property definitions for the Relationship Type. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @object_dict_field(AttributeDefinition) + def attributes(self): + """ + An optional list of attribute definitions for the Relationship Type. + + :type: {:obj:`basestring`: :class:`AttributeDefinition`} + """ + + @object_dict_field(InterfaceDefinition) + def interfaces(self): + """ + An optional list of interface definitions interfaces supported by the Relationship Type. + + :type: {:obj:`basestring`: :class:`InterfaceDefinition`} + """ + + @field_validator(list_type_validator('capability type', convert_name_to_full_type_name, + 'capability_types')) + @primitive_list_field(str) + def valid_target_types(self): + """ + An optional list of one or more names of Capability Types that are valid targets for this + relationship. + + :type: [:obj:`basestring`] + """ + + @cachedmethod + def _get_parent(self, context): + return get_parent_presentation(context, self, convert_name_to_full_type_name, + 'relationship_types') + + @cachedmethod + def _is_descendant(self, context, the_type): + if the_type is None: + return False + elif the_type._name == self._name: + return True + return self._is_descendant(context, the_type._get_parent(context)) + + @cachedmethod + def _get_properties(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'properties')) + + @cachedmethod + def _get_attributes(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'attributes')) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_inherited_interface_definitions(context, self, 'relationship type')) + + def _validate(self, context): + super(RelationshipType, self)._validate(context) + self._get_properties(context) + self._get_attributes(context) + self._get_interfaces(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'valid_target_types', + 'properties', + 'attributes', + 'interfaces')) + + +@has_fields +@implements_specification('3.6.8', 'tosca-simple-1.0') +class NodeType(ExtensiblePresentation): + """ + A Node Type is a reusable entity that defines the type of one or more Node Templates. As such, a + Node Type defines the structure of observable properties via a Properties Definition, the + Requirements and Capabilities of the node as well as its supported interfaces. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_NODE_TYPE>`__ + """ + + @field_validator(derived_from_validator(convert_name_to_full_type_name, 'node_types')) + @primitive_field(str) + def derived_from(self): + """ + An optional parent Node Type name this new Node Type derives from. + + :type: :obj:`basestring` + """ + + @object_field(Version) + def version(self): + """ + An optional version for the Node Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Node Type. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyDefinition) + def properties(self): + """ + An optional list of property definitions for the Node Type. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @object_dict_field(AttributeDefinition) + def attributes(self): + """ + An optional list of attribute definitions for the Node Type. + + :type: {:obj:`basestring`: :class:`AttributeDefinition`} + """ + + @object_sequenced_list_field(RequirementDefinition) + def requirements(self): + """ + An optional sequenced list of requirement definitions for the Node Type. + + ARIA NOTE: The spec seems wrong to make this a sequenced list. It seems that when you have + more than one requirement of the same name, behavior is undefined. The idea is to use the + "occurrences" field if you need to limit the number of requirement assignments. + + :type: list of (str, :class:`RequirementDefinition`) + """ + + @object_dict_field(CapabilityDefinition) + def capabilities(self): + """ + An optional list of capability definitions for the Node Type. + + :type: list of :class:`CapabilityDefinition` + """ + + @object_dict_field(InterfaceDefinition) + def interfaces(self): + """ + An optional list of interface definitions supported by the Node Type. + + :type: {:obj:`basestring`: :class:`InterfaceDefinition`} + """ + + @object_dict_field(ArtifactAssignmentForType) + def artifacts(self): + """ + An optional list of named artifact definitions for the Node Type. + + :type: {:obj:`basestring`: :class:`ArtifactAssignmentForType`} + """ + + @cachedmethod + def _get_parent(self, context): + return get_parent_presentation(context, self, convert_name_to_full_type_name, 'node_types') + + @cachedmethod + def _is_descendant(self, context, the_type): + if the_type is None: + return False + elif the_type._name == self._name: + return True + return self._is_descendant(context, the_type._get_parent(context)) + + @cachedmethod + def _get_properties(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'properties')) + + @cachedmethod + def _get_attributes(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'attributes')) + + @cachedmethod + def _get_requirements(self, context): + return FrozenList(get_inherited_requirement_definitions(context, self)) + + @cachedmethod + def _get_capabilities(self, context): + return FrozenDict(get_inherited_capability_definitions(context, self)) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_inherited_interface_definitions(context, self, 'node type')) + + @cachedmethod + def _get_artifacts(self, context): + return FrozenDict(get_inherited_artifact_definitions(context, self)) + + def _validate(self, context): + super(NodeType, self)._validate(context) + self._get_properties(context) + self._get_attributes(context) + self._get_requirements(context) + self._get_capabilities(context) + self._get_interfaces(context) + self._get_artifacts(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'properties', + 'attributes', + 'interfaces', + 'artifacts', + 'requirements', + 'capabilities')) + + +@has_fields +@implements_specification('3.6.10', 'tosca-simple-1.0') +class GroupType(ExtensiblePresentation): + """ + A Group Type defines logical grouping types for nodes, typically for different management + purposes. Groups can effectively be viewed as logical nodes that are not part of the physical + deployment topology of an application, yet can have capabilities and the ability to attach + policies and interfaces that can be applied (depending on the group type) to its member nodes. + + Conceptually, group definitions allow the creation of logical "membership" relationships to + nodes in a service template that are not a part of the application's explicit requirement + dependencies in the topology template (i.e. those required to actually get the application + deployed and running). Instead, such logical membership allows for the introduction of things + such as group management and uniform application of policies (i.e., requirements that are also + not bound to the application itself) to the group's members. + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_GROUP_TYPE>`__ + """ + + @field_validator(derived_from_validator(convert_name_to_full_type_name, 'group_types')) + @primitive_field(str) + def derived_from(self): + """ + An optional parent Group Type name the Group Type derives from. + + :type: :obj:`basestring` + """ + + @object_field(Version) + def version(self): + """ + An optional version for the Group Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the Group Type. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyDefinition) + def properties(self): + """ + An optional list of property definitions for the Group Type. + + :type: {:obj:`basestring`: :class:`PropertyDefinition`} + """ + + @field_validator(list_type_validator('node type', convert_name_to_full_type_name, 'node_types')) + @primitive_list_field(str) + def members(self): + """ + An optional list of one or more names of Node Types that are valid (allowed) as members of + the Group Type. + + Note: This can be viewed by TOSCA Orchestrators as an implied relationship from the listed + members nodes to the group, but one that does not have operational lifecycle considerations. + For example, if we were to name this as an explicit Relationship Type we might call this + "MemberOf" (group). + + :type: [:obj:`basestring`] + """ + + @object_dict_field(InterfaceDefinition) + def interfaces(self): + """ + An optional list of interface definitions supported by the Group Type. + + :type: {:obj:`basestring`: :class:`InterfaceDefinition`} + """ + + @cachedmethod + def _get_parent(self, context): + return get_parent_presentation(context, self, convert_name_to_full_type_name, + 'group_types') + + @cachedmethod + def _is_descendant(self, context, the_type): + if the_type is None: + return False + elif the_type._name == self._name: + return True + return self._is_descendant(context, the_type._get_parent(context)) + + @cachedmethod + def _get_properties(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'properties')) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_inherited_interface_definitions(context, self, 'group type')) + + def _validate(self, context): + super(GroupType, self)._validate(context) + self._get_properties(context) + self._get_interfaces(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'members', + 'properties', + 'interfaces')) + + +@has_fields +@implements_specification('3.6.11', 'tosca-simple-1.0') +class PolicyType(ExtensiblePresentation): + """ + A Policy Type defines a type of requirement that affects or governs an application or service's + topology at some stage of its lifecycle, but is not explicitly part of the topology itself + (i.e., it does not prevent the application or service from being deployed or run if it did not + exist). + + See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html + #DEFN_ENTITY_POLICY_TYPE>`__ + """ + + @field_validator(derived_from_validator(convert_name_to_full_type_name, 'policy_types')) + @primitive_field(str) + def derived_from(self): + """ + An optional parent Policy Type name the Policy Type derives from. + + :type: :obj:`basestring` + """ + + @object_field(Version) + def version(self): + """ + An optional version for the Policy Type definition. + + :type: :class:`Version` + """ + + @object_field(Description) + def description(self): + """ + The optional description for the Policy Type. + + :type: :class:`Description` + """ + + @object_dict_field(PropertyDefinition) + def properties(self): + """ + An optional list of property definitions for the Policy Type. + + :type: :class:`PropertyDefinition` + """ + + @field_validator(list_node_type_or_group_type_validator) + @primitive_list_field(str) + def targets(self): + """ + An optional list of valid Node Types or Group Types the Policy Type can be applied to. + + Note: This can be viewed by TOSCA Orchestrators as an implied relationship to the target + nodes, but one that does not have operational lifecycle considerations. For example, if we + were to name this as an explicit Relationship Type we might call this "AppliesTo" (node or + group). + + :type: [:obj:`basestring`] + """ + + @cachedmethod + def _get_parent(self, context): + return get_parent_presentation(context, self, convert_name_to_full_type_name, + 'policy_types') + + @cachedmethod + def _get_properties(self, context): + return FrozenDict(get_inherited_parameter_definitions(context, self, 'properties')) + + @cachedmethod + def _get_targets(self, context): + node_types, group_types = get_inherited_targets(context, self) + return FrozenList(node_types), FrozenList(group_types) + + def _validate(self, context): + super(PolicyType, self)._validate(context) + self._get_properties(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'version', + 'derived_from', + 'targets', + 'properties')) |