diff --git a/contrib/devstack/lib/murano b/contrib/devstack/lib/murano
index 0e6380bad..9a48abf2d 100644
--- a/contrib/devstack/lib/murano
+++ b/contrib/devstack/lib/murano
@@ -134,8 +134,8 @@ function init_murano() {
recreate_database murano utf8
$MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE db-sync
- $MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/packages/core
- $MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/packages/activedirectory
+ $MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/io.murano
+ $MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/io.murano.windows.ActiveDirectory
}
diff --git a/meta/packages/activedirectory/Classes/ad.yaml b/meta/io.murano.windows.ActiveDirectory/Classes/ActiveDirectory.yaml
similarity index 72%
rename from meta/packages/activedirectory/Classes/ad.yaml
rename to meta/io.murano.windows.ActiveDirectory/Classes/ActiveDirectory.yaml
index 05125276f..7f037ef71 100644
--- a/meta/packages/activedirectory/Classes/ad.yaml
+++ b/meta/io.murano.windows.ActiveDirectory/Classes/ActiveDirectory.yaml
@@ -1,8 +1,7 @@
Namespaces:
- =: io.murano.services.windows.activeDirectory
+ =: io.murano.windows.activeDirectory
std: io.murano
sys: io.murano.system
- win: io.murano.services.windows
Name: ActiveDirectory
@@ -29,5 +28,9 @@ Properties:
Workflow:
deploy:
Body:
- - $.primaryController.deploy()
- - $.secondaryControllers.pselect($.deploy())
+ - $.primaryController.deploy()
+ - $.secondaryControllers.pselect($.deploy())
+ - $.reportDeployed()
+
+ destroy:
+ - $.reportDestroyed()
diff --git a/meta/packages/activedirectory/Classes/controller.yaml b/meta/io.murano.windows.ActiveDirectory/Classes/Controller.yaml
similarity index 75%
rename from meta/packages/activedirectory/Classes/controller.yaml
rename to meta/io.murano.windows.ActiveDirectory/Classes/Controller.yaml
index 0e5deb6bf..76fdb4656 100644
--- a/meta/packages/activedirectory/Classes/controller.yaml
+++ b/meta/io.murano.windows.ActiveDirectory/Classes/Controller.yaml
@@ -1,8 +1,8 @@
Namespaces:
- =: io.murano.services.windows.activeDirectory
+ =: io.murano.windows.activeDirectory
std: io.murano
sys: io.murano.system
- win: io.murano.services.windows
+ win: io.murano.windows
Name: Controller
diff --git a/meta/io.murano.windows.ActiveDirectory/Classes/DomainHost.yaml b/meta/io.murano.windows.ActiveDirectory/Classes/DomainHost.yaml
new file mode 100644
index 000000000..9633f9bbc
--- /dev/null
+++ b/meta/io.murano.windows.ActiveDirectory/Classes/DomainHost.yaml
@@ -0,0 +1,20 @@
+Namespaces:
+ =: io.murano.windows
+ ad: io.murano.windows.activeDirectory
+
+Name: DomainHost
+
+Extends: Host
+
+Properties:
+ domain:
+ Contract: $.class(ad:ActiveDirectory).notNull()
+
+Workflow:
+ deploy:
+ Arguments:
+ Body:
+ - $.super($.deploy())
+ #- $.joinDomain($.domain)
+ # Workaround against broken ResourceManager:
+ - $.super($.joinDomain($this.domain))
diff --git a/meta/io.murano.windows.ActiveDirectory/Classes/Host.yaml b/meta/io.murano.windows.ActiveDirectory/Classes/Host.yaml
new file mode 100644
index 000000000..9294e79dd
--- /dev/null
+++ b/meta/io.murano.windows.ActiveDirectory/Classes/Host.yaml
@@ -0,0 +1,49 @@
+Namespaces:
+ =: io.murano.windows
+ ad: io.murano.windows.activeDirectory
+ res: io.murano.resources
+ sys: io.murano.system
+
+Name: Host
+
+Extends: res:Instance
+
+Properties:
+ adminAccountName:
+ Contract: $.string().notNull()
+ Default: Administrator
+
+ adminPassword:
+ Contract: $.string().notNull()
+
+Workflow:
+ initialize:
+ Body:
+ - $.super($.initialize())
+
+ deploy:
+ Body:
+ - $.super($.deploy())
+
+ - $resources: new(sys:Resources)
+ - $template: $resources.json('SetPassword.template').bind(dict(
+ adminPassword => $.adminPassword
+ ))
+ - $.agent.send($template, $resources)
+
+ joinDomain:
+ Arguments:
+ - domain:
+ Contract: $.class(ad:ActiveDirectory).notNull()
+ Body:
+
+ - $resources: new(sys:Resources)
+ - $template: $resources.json('JoinDomain.template').bind(dict(
+ domain => $domain.name,
+ domainUser => $domain.adminAccountName,
+ domainPassword => $domain.adminPassword,
+ ouPath => '',
+ dnsIp => $domain.primaryController.dnsIp
+ ))
+ - $.agent.call($template, $resources)
+
diff --git a/meta/packages/activedirectory/Classes/primary_controller.yaml b/meta/io.murano.windows.ActiveDirectory/Classes/PrimaryController.yaml
similarity index 80%
rename from meta/packages/activedirectory/Classes/primary_controller.yaml
rename to meta/io.murano.windows.ActiveDirectory/Classes/PrimaryController.yaml
index 008c657ca..30883f6b3 100644
--- a/meta/packages/activedirectory/Classes/primary_controller.yaml
+++ b/meta/io.murano.windows.ActiveDirectory/Classes/PrimaryController.yaml
@@ -1,8 +1,7 @@
Namespaces:
- =: io.murano.services.windows.activeDirectory
+ =: io.murano.windows.activeDirectory
std: io.murano
sys: io.murano.system
- win: io.murano.services.windows
Name: PrimaryController
@@ -22,7 +21,6 @@ Workflow:
deploy:
Arguments:
Body:
- - $.debugPrint('Deploying Primary Controller for domain {0}'.format($this.domain.name))
- $.super($.deploy())
- $resources: new(io.murano.system.Resources)
- $template: $resources.json('CreatePrimaryDC.template').bind(dict(
diff --git a/meta/packages/activedirectory/Classes/secondary_controller.yaml b/meta/io.murano.windows.ActiveDirectory/Classes/SecondaryController.yaml
similarity index 82%
rename from meta/packages/activedirectory/Classes/secondary_controller.yaml
rename to meta/io.murano.windows.ActiveDirectory/Classes/SecondaryController.yaml
index b57d8c2a6..ebd346645 100644
--- a/meta/packages/activedirectory/Classes/secondary_controller.yaml
+++ b/meta/io.murano.windows.ActiveDirectory/Classes/SecondaryController.yaml
@@ -1,5 +1,5 @@
Namespaces:
- =: io.murano.services.windows.activeDirectory
+ =: io.murano.windows.activeDirectory
std: io.murano
sys: io.murano.system
@@ -15,7 +15,6 @@ Workflow:
deploy:
Body:
- - $.debugPrint('Deploying Secondary Controller for domain {0}'.format($this.domain.name))
- $.super($.deploy())
- $.host.joinDomain($.domain)
- $resources: new(sys:Resources)
diff --git a/meta/packages/activedirectory/Resources/AskDnsIp.template b/meta/io.murano.windows.ActiveDirectory/Resources/AskDnsIp.template
similarity index 100%
rename from meta/packages/activedirectory/Resources/AskDnsIp.template
rename to meta/io.murano.windows.ActiveDirectory/Resources/AskDnsIp.template
diff --git a/meta/packages/activedirectory/Resources/CreatePrimaryDC.template b/meta/io.murano.windows.ActiveDirectory/Resources/CreatePrimaryDC.template
similarity index 100%
rename from meta/packages/activedirectory/Resources/CreatePrimaryDC.template
rename to meta/io.murano.windows.ActiveDirectory/Resources/CreatePrimaryDC.template
diff --git a/meta/packages/activedirectory/Resources/CreateSecondaryDC.template b/meta/io.murano.windows.ActiveDirectory/Resources/CreateSecondaryDC.template
similarity index 100%
rename from meta/packages/activedirectory/Resources/CreateSecondaryDC.template
rename to meta/io.murano.windows.ActiveDirectory/Resources/CreateSecondaryDC.template
diff --git a/meta/io.murano.windows.ActiveDirectory/Resources/JoinDomain.template b/meta/io.murano.windows.ActiveDirectory/Resources/JoinDomain.template
new file mode 100644
index 000000000..3d8cbeff8
--- /dev/null
+++ b/meta/io.murano.windows.ActiveDirectory/Resources/JoinDomain.template
@@ -0,0 +1,25 @@
+{
+ "Scripts": [
+ "ImportCoreFunctions.ps1",
+ "Join-Domain.ps1"
+ ],
+ "Commands": [
+ {
+ "Name": "Set-NetworkAdapterConfiguration",
+ "Arguments": {
+ "FirstAvailable": true,
+ "DNSServer": "$dnsIp"
+ }
+ },
+ {
+ "Name": "Join-Domain",
+ "Arguments": {
+ "Username": "$domainUser",
+ "Password": "$domainPassword",
+ "DomainName": "$domain",
+ "OUPath": "$ouPath"
+ }
+ }
+ ],
+ "RebootOnCompletion": 1
+}
\ No newline at end of file
diff --git a/meta/io.murano.windows.ActiveDirectory/Resources/SetPassword.template b/meta/io.murano.windows.ActiveDirectory/Resources/SetPassword.template
new file mode 100644
index 000000000..101db0ead
--- /dev/null
+++ b/meta/io.murano.windows.ActiveDirectory/Resources/SetPassword.template
@@ -0,0 +1,17 @@
+{
+ "Scripts": [
+ "ImportCoreFunctions.ps1",
+ "Set-LocalUserPassword.ps1"
+ ],
+ "Commands": [
+ {
+ "Name": "Set-LocalUserPassword",
+ "Arguments": {
+ "UserName": "Administrator",
+ "Password": "$adminPassword",
+ "Force": true
+ }
+ }
+ ],
+ "RebootOnCompletion": 0
+}
\ No newline at end of file
diff --git a/meta/packages/activedirectory/Resources/scripts/Get-DnsListeningIpAddress.ps1 b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Get-DnsListeningIpAddress.ps1
similarity index 100%
rename from meta/packages/activedirectory/Resources/scripts/Get-DnsListeningIpAddress.ps1
rename to meta/io.murano.windows.ActiveDirectory/Resources/scripts/Get-DnsListeningIpAddress.ps1
diff --git a/meta/packages/activedirectory/Resources/scripts/ImportCoreFunctions.ps1 b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/ImportCoreFunctions.ps1
similarity index 100%
rename from meta/packages/activedirectory/Resources/scripts/ImportCoreFunctions.ps1
rename to meta/io.murano.windows.ActiveDirectory/Resources/scripts/ImportCoreFunctions.ps1
diff --git a/meta/packages/activedirectory/Resources/scripts/Install-RolePrimaryDomainController.ps1 b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Install-RolePrimaryDomainController.ps1
similarity index 100%
rename from meta/packages/activedirectory/Resources/scripts/Install-RolePrimaryDomainController.ps1
rename to meta/io.murano.windows.ActiveDirectory/Resources/scripts/Install-RolePrimaryDomainController.ps1
diff --git a/meta/packages/activedirectory/Resources/scripts/Install-RoleSecondaryDomainController.ps1 b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Install-RoleSecondaryDomainController.ps1
similarity index 100%
rename from meta/packages/activedirectory/Resources/scripts/Install-RoleSecondaryDomainController.ps1
rename to meta/io.murano.windows.ActiveDirectory/Resources/scripts/Install-RoleSecondaryDomainController.ps1
diff --git a/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Join-Domain.ps1 b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Join-Domain.ps1
new file mode 100644
index 000000000..403ef798d
--- /dev/null
+++ b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Join-Domain.ps1
@@ -0,0 +1,67 @@
+
+trap {
+ &$TrapHandler
+}
+
+
+Function Join-Domain {
+<#
+.SYNOPSIS
+Executes "Join domain" action.
+
+Requires 'CoreFunctions' module
+#>
+ param (
+ [String] $DomainName = '',
+ [String] $UserName = '',
+ [String] $Password = '',
+ [String] $OUPath = '',
+ [Switch] $AllowRestart
+ )
+ begin {
+ Show-InvocationInfo $MyInvocation
+ }
+ end {
+ Show-InvocationInfo $MyInvocation -End
+ }
+ process {
+ trap {
+ &$TrapHandler
+ }
+
+ if ($UserName -eq '') {
+ $UserName = 'Administrator'
+ }
+
+ $Credential = New-Credential -UserName "$DomainName\$UserName" -Password $Password
+
+
+ if (Test-ComputerName -DomainName $DomainName -ErrorAction 'SilentlyContinue') {
+ Write-LogWarning "Computer already joined to domain '$DomainName'"
+ }
+ else {
+ Write-Log "Joining computer to domain '$DomainName' ..."
+
+ if ($OUPath -eq '') {
+ Add-Computer -DomainName $DomainName -Credential $Credential -Force
+ }
+ else {
+ Add-Computer -DomainName $DomainName -Credential $Credential -OUPath $OUPath -Force
+ }
+
+ $null = Exec 'ipconfig' @('/registerdns') -RedirectStreams
+
+ Write-Log "Waiting 30 seconds to restart ..."
+ Start-Sleep -Seconds 30
+ <#
+ if ($AllowRestart) {
+ Write-Log "Restarting computer ..."
+ Restart-Computer -Force
+ }
+ else {
+ Write-Log "Please restart the computer now."
+ }
+ #>
+ }
+ }
+}
diff --git a/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Set-LocalUserPassword.ps1 b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Set-LocalUserPassword.ps1
new file mode 100644
index 000000000..8708a0f4a
--- /dev/null
+++ b/meta/io.murano.windows.ActiveDirectory/Resources/scripts/Set-LocalUserPassword.ps1
@@ -0,0 +1,37 @@
+
+trap {
+ &$TrapHandler
+}
+
+
+Function Set-LocalUserPassword {
+ param (
+ [String] $UserName,
+ [String] $Password,
+ [Switch] $Force
+ )
+ begin {
+ Show-InvocationInfo $MyInvocation
+ }
+ end {
+ Show-InvocationInfo $MyInvocation -End
+ }
+ process {
+ trap {
+ &$TrapHandler
+ }
+
+ if ((Get-WmiObject Win32_UserAccount -Filter "LocalAccount = 'True' AND Name='$UserName'") -eq $null) {
+ throw "Unable to find local user account '$UserName'"
+ }
+
+ if ($Force) {
+ Write-Log "Changing password for user '$UserName' to '*****'" # :)
+ $null = ([ADSI] "WinNT://./$UserName").SetPassword($Password)
+ }
+ else {
+ Write-LogWarning "You are trying to change password for user '$UserName'. To do this please run the command again with -Force parameter."
+ }
+ }
+}
+
diff --git a/meta/packages/activedirectory/UI/ui.yaml b/meta/io.murano.windows.ActiveDirectory/UI/ui.yaml
similarity index 100%
rename from meta/packages/activedirectory/UI/ui.yaml
rename to meta/io.murano.windows.ActiveDirectory/UI/ui.yaml
diff --git a/meta/packages/activedirectory/logo2.png b/meta/io.murano.windows.ActiveDirectory/logo2.png
similarity index 100%
rename from meta/packages/activedirectory/logo2.png
rename to meta/io.murano.windows.ActiveDirectory/logo2.png
diff --git a/meta/io.murano.windows.ActiveDirectory/manifest.yaml b/meta/io.murano.windows.ActiveDirectory/manifest.yaml
new file mode 100644
index 000000000..a5809752a
--- /dev/null
+++ b/meta/io.murano.windows.ActiveDirectory/manifest.yaml
@@ -0,0 +1,27 @@
+Format: 1.0
+
+Type: Application
+
+FullName: io.murano.windows.ActiveDirectory
+
+Name: Active Directory
+
+Description: |
+ A domain service hosted in Windows environment by using Active Directory Role.
+ May be clustered by combining a number of secondary domain controllers with one primary
+
+Author: 'murano.io'
+
+Tags: [Windows, Domain, demo, win2012, microsoft]
+
+Classes:
+ io.murano.windows.Host: Host.yaml
+ io.murano.windows.DomainHost: DomainHost.yaml
+ io.murano.windows.activeDirectory.ActiveDirectory: ActiveDirectory.yaml
+ io.murano.windows.activeDirectory.Controller: Controller.yaml
+ io.murano.windows.activeDirectory.PrimaryController: PrimaryController.yaml
+ io.murano.windows.activeDirectory.SecondaryController: SecondaryController.yaml
+
+# UI: ui.yaml # default to ui.yaml, will use default if skipped
+
+Logo: logo2.png # defaults to logo.png, will use default if skipped
\ No newline at end of file
diff --git a/meta/packages/core/Classes/application.yaml b/meta/io.murano/Classes/Application.yaml
similarity index 100%
rename from meta/packages/core/Classes/application.yaml
rename to meta/io.murano/Classes/Application.yaml
diff --git a/meta/packages/core/Classes/environment.yaml b/meta/io.murano/Classes/Environment.yaml
similarity index 100%
rename from meta/packages/core/Classes/environment.yaml
rename to meta/io.murano/Classes/Environment.yaml
diff --git a/meta/packages/core/Classes/object.yaml b/meta/io.murano/Classes/Object.yaml
similarity index 100%
rename from meta/packages/core/Classes/object.yaml
rename to meta/io.murano/Classes/Object.yaml
diff --git a/meta/io.murano/Classes/resources/Instance.yaml b/meta/io.murano/Classes/resources/Instance.yaml
new file mode 100644
index 000000000..8f702b379
--- /dev/null
+++ b/meta/io.murano/Classes/resources/Instance.yaml
@@ -0,0 +1,81 @@
+Namespaces:
+ =: io.murano.resources
+ sys: io.murano.system
+
+
+Name: Instance
+
+
+Properties:
+ name:
+ Contract: $.string().notNull()
+ flavor:
+ Contract: $.string().notNull()
+ image:
+ Contract: $.string().notNull()
+
+ agent:
+ Contract: $.class(sys:Agent)
+ Type: Runtime
+
+
+Workflow:
+ initialize:
+ Body:
+ - $.environment: $.find(Environment).require()
+ - $.agent: new(sys:Agent, host => $)
+ - $.resources: new(sys:Resources)
+
+ deploy:
+ Body:
+ - $userData: $.prepareUserData()
+ - $template:
+ Resources:
+ $.name:
+ Type: 'AWS::EC2::Instance'
+ Properties:
+ InstanceType: $.flavor
+ ImageId: $.image
+ UserData: $userData
+ - $.environment.stack.updateTemplate($template)
+ - $.environment.stack.push()
+ - $.environment.instanceNotifier.trackApplication($this)
+
+ destroy:
+ Body:
+ - $template: $.environment.stack.current()
+ - $patchBlock:
+ op: remove,
+ path: format('/Resources/{0}', $.name)
+ - $template: patch($template, $patchBlock)
+ - $.environment.stack.setTemplate($template)
+ - $.environment.stack.push()
+ - $.environment.instanceNotifier.untrackApplication($this)
+
+ prepareUserData:
+ Body:
+ - If: !yaql "'w' in toLower($.image)"
+ Then:
+ - $configFile: $.resources.string('Agent-v1.template')
+ - $initScript: $.resources.string('windows-init.ps1')
+ Else:
+ - $configFile: $.resources.string('Agent-v2.template')
+ - $initScript: $.resources.string('linux-init.sh')
+
+ - $configReplacements:
+ "%RABBITMQ_HOST%": config(rabbitmq, host)
+ "%RABBITMQ_PORT%": config(rabbitmq, port)
+ "%RABBITMQ_USER%": config(rabbitmq, login)
+ "%RABBITMQ_PASSWORD%": config(rabbitmq, password)
+ "%RABBITMQ_VHOST%": config(rabbitmq, virtual_host)
+ "%RABBITMQ_SSL%": str(config(rabbitmq, ssl)).toLower()
+ "%RABBITMQ_INPUT_QUEUE%": $.agent.queueName()
+ "%RESULT_QUEUE%": $.environment.agentListener.queueName()
+
+ - $scriptReplacements:
+ "%AGENT_CONFIG_BASE64%": base64encode($configFile.replace($configReplacements))
+ "%INTERNAL_HOSTNAME%": $.name
+ "%MURANO_SERVER_ADDRESS%": coalesce(config(file_server), config(rabbitmq, host))
+ "%CA_ROOT_CERT_BASE64%": ""
+
+ - Return: $initScript.replace($scriptReplacements)
\ No newline at end of file
diff --git a/meta/io.murano/Resources/Agent-v1.template b/meta/io.murano/Resources/Agent-v1.template
new file mode 100644
index 000000000..839abe8ac
--- /dev/null
+++ b/meta/io.murano/Resources/Agent-v1.template
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/meta/io.murano/Resources/Agent-v2.template b/meta/io.murano/Resources/Agent-v2.template
new file mode 100644
index 000000000..b1f3db9d8
--- /dev/null
+++ b/meta/io.murano/Resources/Agent-v2.template
@@ -0,0 +1,35 @@
+[DEFAULT]
+debug=True
+verbose=True
+log_file = /var/log/murano-agnet.log
+
+storage=/var/murano/plans
+
+[rabbitmq]
+
+# Input queue name
+input_queue = %RABBITMQ_INPUT_QUEUE%
+
+# Output routing key (usually queue name)
+result_routing_key = %RESULT_QUEUE%
+
+# Connection parameters to RabbitMQ service
+
+# Hostname or IP address where RabbitMQ is located.
+host = %RABBITMQ_HOST%
+
+# RabbitMQ port (5672 is a default)
+port = %RABBITMQ_PORT%
+
+# Use SSL for RabbitMQ connections (True or False)
+ssl = %RABBITMQ_SSL%
+
+# Path to SSL CA certificate or empty to allow self signed server certificate
+ca_certs =
+
+# RabbitMQ credentials. Fresh RabbitMQ installation has "guest" account with "guest" password.
+login = %RABBITMQ_USER%
+password = %RABBITMQ_PASSWORD%
+
+# RabbitMQ virtual host (vhost). Fresh RabbitMQ installation has "/" vhost preconfigured.
+virtual_host = %RABBITMQ_VHOST%
diff --git a/meta/io.murano/Resources/linux-init.sh b/meta/io.murano/Resources/linux-init.sh
new file mode 100644
index 000000000..9667f4b7a
--- /dev/null
+++ b/meta/io.murano/Resources/linux-init.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+service murano-agent stop
+
+AgentConfigBase64='%AGENT_CONFIG_BASE64%'
+
+mkdir /etc/murano
+echo $AgentConfigBase64 | base64 -d > /etc/murano/agent.conf
+chmod 664 /etc/murano/agent.conf
+
+service murano-agent start
diff --git a/meta/io.murano/Resources/windows-init.ps1 b/meta/io.murano/Resources/windows-init.ps1
new file mode 100644
index 000000000..73ef8bbaf
--- /dev/null
+++ b/meta/io.murano/Resources/windows-init.ps1
@@ -0,0 +1,68 @@
+#ps1
+
+$WindowsAgentConfigBase64 = '%AGENT_CONFIG_BASE64%'
+$WindowsAgentConfigFile = "C:\Murano\Agent\WindowsAgent.exe.config"
+$WindowsAgentLogFile = "C:\Murano\Agent\log.txt"
+
+$NewComputerName = '%INTERNAL_HOSTNAME%'
+$MuranoFileShare = '\\%MURANO_SERVER_ADDRESS%\share'
+
+$CaRootCertBase64 = "%CA_ROOT_CERT_BASE64%"
+$CaRootCertFile = "C:\Murano\ca.cert"
+
+$RestartRequired = $false
+
+Import-Module CoreFunctions
+Initialize-Logger 'CloudBase-Init' 'C:\Murano\PowerShell.log'
+
+$ErrorActionPreference = 'Stop'
+
+trap {
+ Write-LogError ''
+ Write-LogError $_ -EntireObject
+ Write-LogError ''
+ exit 1
+}
+
+Write-Log "Importing CA certificate ..."
+if ($CaRootCertBase64 -eq '') {
+ Write-Log "Importing CA certificate ... skipped"
+}
+else {
+ ConvertFrom-Base64String -Base64String $CaRootCertBase64 -Path $CaRootCertFile
+ $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $CaRootCertFile
+ $store = New-Object System.Security.Cryptography.X509Certificates.X509Store("AuthRoot","LocalMachine")
+ $store.Open("MaxAllowed")
+ $store.Add($cert)
+ $store.Close()
+ Write-Log "Importing CA certificate ... done"
+}
+
+Write-Log "Updating Murano Windows Agent."
+Stop-Service "Murano Agent"
+Backup-File $WindowsAgentConfigFile
+Remove-Item $WindowsAgentConfigFile -Force -ErrorAction 'SilentlyContinue'
+Remove-Item $WindowsAgentLogFile -Force -ErrorAction 'SilentlyContinue'
+ConvertFrom-Base64String -Base64String $WindowsAgentConfigBase64 -Path $WindowsAgentConfigFile
+Exec sc.exe 'config','"Murano Agent"','start=','delayed-auto'
+Write-Log "Service has been updated."
+
+Write-Log "Adding environment variable 'MuranoFileShare' = '$MuranoFileShare' ..."
+[Environment]::SetEnvironmentVariable('MuranoFileShare', $MuranoFileShare, [EnvironmentVariableTarget]::Machine)
+Write-Log "Environment variable added."
+
+Write-Log "Renaming computer to '$NewComputerName' ..."
+$null = Rename-Computer -NewName $NewComputerName -Force
+
+Write-Log "New name assigned, restart required."
+$RestartRequired = $true
+
+
+Write-Log 'All done!'
+if ( $RestartRequired ) {
+ Write-Log "Restarting computer ..."
+ Restart-Computer -Force
+}
+else {
+ Start-Service 'Murano Agent'
+}
diff --git a/meta/io.murano/manifest.yaml b/meta/io.murano/manifest.yaml
new file mode 100644
index 000000000..11b771e7d
--- /dev/null
+++ b/meta/io.murano/manifest.yaml
@@ -0,0 +1,21 @@
+Format: 1.0
+
+Type: Library
+
+FullName: io.murano
+
+Name: Core library
+
+Description: |
+ Core MuranoPL library
+
+Author: 'murano.io'
+
+Tags: [MuranoPL]
+
+Classes:
+ io.murano.Object: Object.yaml
+ io.murano.Environment: Environment.yaml
+ io.murano.Application: Application.yaml
+
+ io.murano.resources.Instance: resources/Instance.yaml
\ No newline at end of file
diff --git a/meta/packages/activedirectory/manifest.yaml b/meta/packages/activedirectory/manifest.yaml
deleted file mode 100644
index 573523dd0..000000000
--- a/meta/packages/activedirectory/manifest.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-Format: 1.0
-Type: Application
-FullName: io.murano.windows.activeDirectory.ActiveDirectory
-Name: Active Directory
-Description: |
- A domain service hosted in Windows environment by using Active Directory Role.
- May be clustered by combining a number of secondary domain controllers with one primary
-Author: 'murano.io'
-Tags: [Windows, Domain, demo, win2012, microsoft]
-Classes:
- io.murano.windows.activeDirectory.ActiveDirectory: ad.yaml
- io.murano.windows.activeDirectory.Controller: controller.yaml
- io.murano.windows.activeDirectory.PrimaryController: primary_controller.yaml
- io.murano.windows.activeDirectory.SecondaryController: secondary_controller.yaml
-# UI: ui.yaml # default to ui.yaml, will use default if skipped
-Logo: logo2.png # defaults to logo.png, will use default if skipped
\ No newline at end of file
diff --git a/meta/packages/core/manifest.yaml b/meta/packages/core/manifest.yaml
deleted file mode 100644
index abe16bb68..000000000
--- a/meta/packages/core/manifest.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-Format: 1.0
-Type: Library
-FullName: io.murano.core
-Name: Core library
-Description: |
- Core MuranoPL library
-Author: 'murano.io'
-Tags: [MuranoPL]
-Classes:
- io.murano.Object: object.yaml
- io.murano.Environment: environment.yaml
- io.murano.Application: application.yaml
\ No newline at end of file
diff --git a/muranoapi/cmd/manage.py b/muranoapi/cmd/manage.py
index 6628802fb..f44edb146 100644
--- a/muranoapi/cmd/manage.py
+++ b/muranoapi/cmd/manage.py
@@ -92,3 +92,7 @@ def main():
CONF.command.func()
except Exception as e:
sys.exit("ERROR: %s" % e)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/muranoapi/common/engine.py b/muranoapi/common/engine.py
index 0acba0f09..917e069da 100644
--- a/muranoapi/common/engine.py
+++ b/muranoapi/common/engine.py
@@ -52,7 +52,8 @@ class TaskProcessingEndpoint(object):
exc = executor.MuranoDslExecutor(cl, env)
obj = exc.load(task['model'])
- obj.type.invoke('deploy', exc, obj, {})
+ if obj is not None:
+ obj.type.invoke('deploy', exc, obj, {})
s_res = results_serializer.serialize(obj, exc)
rpc.api().process_result(s_res)
diff --git a/muranoapi/db/services/environments.py b/muranoapi/db/services/environments.py
index 916c6bc0f..a76737f23 100644
--- a/muranoapi/db/services/environments.py
+++ b/muranoapi/db/services/environments.py
@@ -122,13 +122,15 @@ class EnvironmentServices(object):
#preparing data for removal from conductor
env = environment.description
- env['services'] = {}
- env['deleted'] = True
+ env['Objects'] = None
- #Set X-Auth-Token for conductor
- env['token'] = token
+ data = {
+ 'model': env,
+ 'token': token,
+ 'tenant_id': environment.tenant_id
+ }
- rpc.engine().handle_task(env)
+ rpc.engine().handle_task(data)
with unit.begin():
unit.delete(environment)
diff --git a/muranoapi/dsl/executor.py b/muranoapi/dsl/executor.py
index dd0368b7d..8bb6cd5ca 100644
--- a/muranoapi/dsl/executor.py
+++ b/muranoapi/dsl/executor.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
import functools
import inspect
import types
@@ -216,5 +217,49 @@ class MuranoDslExecutor(object):
if not isinstance(data, types.DictionaryType):
raise TypeError()
self._attribute_store.load(data.get('Attributes') or [])
- return self._object_store.load(data.get('Objects') or {},
- None, self._root_context)
+ result = self._object_store.load(data.get('Objects') or {},
+ None, self._root_context)
+ self.cleanup(data)
+ return result
+
+ def cleanup(self, data):
+ objects_copy = data.get('ObjectsCopy')
+ if not objects_copy:
+ return
+ gc_object_store = object_store.ObjectStore(self._class_loader)
+ gc_object_store.load(objects_copy, None, self._root_context)
+ objects_to_clean = []
+ for object_id in self._list_potential_object_ids(objects_copy):
+ if gc_object_store.has(object_id) \
+ and not self._object_store.has(object_id):
+ obj = gc_object_store.get(object_id)
+ objects_to_clean.append(obj)
+ if objects_to_clean:
+ backup = self._object_store
+ try:
+ self._object_store = gc_object_store
+ for obj in objects_to_clean:
+ methods = obj.type.find_method('destroy')
+ for cls, method in methods:
+ try:
+ cls.invoke(method, self, obj, {})
+ except Exception:
+ pass
+ finally:
+ self._object_store = backup
+
+ def _list_potential_object_ids(self, data):
+ if isinstance(data, types.DictionaryType):
+ for val in data.values():
+ for res in self._list_potential_object_ids(val):
+ yield res
+ sys_dict = data.get('?')
+ if isinstance(sys_dict, types.DictionaryType) \
+ and sys_dict.get('id') \
+ and sys_dict.get('type'):
+ yield sys_dict['id']
+ elif isinstance(data, collections.Iterable) and not isinstance(
+ data, types.StringTypes):
+ for val in data:
+ for res in self._list_potential_object_ids(val):
+ yield res
diff --git a/muranoapi/dsl/object_store.py b/muranoapi/dsl/object_store.py
index 98671ac0d..6970a012f 100644
--- a/muranoapi/dsl/object_store.py
+++ b/muranoapi/dsl/object_store.py
@@ -39,12 +39,17 @@ class ObjectStore(object):
return self._parent_store.get(object_id)
return None
+ def has(self, object_id):
+ return object_id in self._store
+
def put(self, murano_object):
self._store[murano_object.object_id] = murano_object
def load(self, value, parent, context, defaults=None):
#tmp_store = ObjectStore(self._class_loader, self)
+ if value is None:
+ return None
if '?' not in value or 'type' not in value['?']:
raise ValueError()
system_key = value['?']
diff --git a/muranoapi/dsl/results_serializer.py b/muranoapi/dsl/results_serializer.py
index ca7b39622..d8f35592b 100644
--- a/muranoapi/dsl/results_serializer.py
+++ b/muranoapi/dsl/results_serializer.py
@@ -23,13 +23,19 @@ class ObjRef(object):
def serialize(root_object, executor):
- serialized_objects = set()
- tree = _pass1_serialize(root_object, None, serialized_objects)
- _pass2_serialize(tree, serialized_objects)
+ if root_object is None:
+ tree = None
+ attributes = []
+ else:
+ serialized_objects = set()
+ tree = _pass1_serialize(root_object, None, serialized_objects)
+ _pass2_serialize(tree, serialized_objects)
+ attributes = executor.attribute_store.serialize(serialized_objects)
return {
'Objects': tree,
- 'Attributes': executor.attribute_store.serialize(serialized_objects)
+ 'ObjectsCopy': tree,
+ 'Attributes': attributes
}
diff --git a/muranoapi/engine/system/heat_stack.py b/muranoapi/engine/system/heat_stack.py
index 1cc0b439f..7220a699e 100644
--- a/muranoapi/engine/system/heat_stack.py
+++ b/muranoapi/engine/system/heat_stack.py
@@ -166,21 +166,25 @@ class HeatStack(murano_object.MuranoObject):
current_status = self._get_status()
if current_status == 'NOT_FOUND':
- self._heat_client.stacks.create(
- stack_name=self._name,
- parameters=self._parameters,
- template=self._template,
- disable_rollback=False)
+ if self._template.get('Resources'):
+ self._heat_client.stacks.create(
+ stack_name=self._name,
+ parameters=self._parameters,
+ template=self._template,
+ disable_rollback=False)
- self._wait_state(
- lambda status: status == 'CREATE_COMPLETE')
+ self._wait_state(
+ lambda status: status == 'CREATE_COMPLETE')
else:
- self._heat_client.stacks.update(
- stack_id=self._name,
- parameters=self._parameters,
- template=self._template)
- self._wait_state(
- lambda status: status == 'UPDATE_COMPLETE')
+ if self._template.get('Resources'):
+ self._heat_client.stacks.update(
+ stack_id=self._name,
+ parameters=self._parameters,
+ template=self._template)
+ self._wait_state(
+ lambda status: status == 'UPDATE_COMPLETE')
+ else:
+ self.delete()
self._applied = True
@@ -191,3 +195,5 @@ class HeatStack(murano_object.MuranoObject):
stack_id=self._name)
self._wait_state(
lambda status: status in ('DELETE_COMPLETE', 'NOT_FOUND'))
+ self._template = {}
+ self._applied = True
diff --git a/muranoapi/engine/system/yaql_functions.py b/muranoapi/engine/system/yaql_functions.py
index e74410d1c..e74ca8345 100644
--- a/muranoapi/engine/system/yaql_functions.py
+++ b/muranoapi/engine/system/yaql_functions.py
@@ -17,6 +17,8 @@ import base64
import re
import types
+import jsonpatch
+import jsonpointer
import yaql.context
import muranoapi.common.config as cfg
@@ -188,6 +190,18 @@ def _pselect(collection, composer):
return helpers.parallel_select(collection(), composer)
+def _patch(obj, patch):
+ obj = obj()
+ patch = patch()
+ if not isinstance(patch, types.ListType):
+ patch = [patch]
+ patch = jsonpatch.JsonPatch(patch)
+ try:
+ return patch.apply(obj)
+ except jsonpointer.JsonPointerException:
+ return obj
+
+
def register(context):
context.register_function(
lambda json, mappings: _transform_json(json(), mappings()), 'bind')
@@ -213,3 +227,4 @@ def register(context):
context.register_function(_substr, 'substr')
context.register_function(_str, 'str')
context.register_function(_int, 'int')
+ context.register_function(_patch, 'patch')
diff --git a/muranoapi/openstack/common/exception.py b/muranoapi/openstack/common/exception.py
index d145e804c..db55cd214 100644
--- a/muranoapi/openstack/common/exception.py
+++ b/muranoapi/openstack/common/exception.py
@@ -124,7 +124,7 @@ class OpenstackException(Exception):
if _FATAL_EXCEPTION_FORMAT_ERRORS:
raise
else:
- # at least get the core message out if something happened
+ # at least get the io.murano message out if something happened
self._error_string = self.msg_fmt
def __str__(self):
diff --git a/requirements.txt b/requirements.txt
index 7d3bcb95c..22f196b18 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,6 +18,7 @@ iso8601>=0.1.8
six>=1.5.2
netaddr>=0.7.6
PyYAML>=3.1.0
+jsonpatch>=1.1
# Note you will need gcc buildtools installed and must
# have installed libxml headers for lxml to be successfully