From e5b716a0a2d5684e3b4701ef14d368fe7345d393 Mon Sep 17 00:00:00 2001 From: Luis Toledo Date: Fri, 6 Aug 2021 16:00:09 -0400 Subject: [PATCH 1/2] adding option to set Azure key from the key storage --- .../azure/plugin/AzureFailureReason.groovy | 9 +++ .../plugin/AzureResourceModelSource.groovy | 14 +++- .../AzureResourceModelSourceFactory.groovy | 15 ++++- .../plugins/azure/util/AzurePluginUtil.groovy | 20 +++++- .../AzureResourceModelSourceSpec.groovy | 64 +++++++++++++++++-- 5 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 src/main/groovy/com/rundeck/plugins/azure/plugin/AzureFailureReason.groovy diff --git a/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureFailureReason.groovy b/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureFailureReason.groovy new file mode 100644 index 0000000..07d1eba --- /dev/null +++ b/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureFailureReason.groovy @@ -0,0 +1,9 @@ +package com.rundeck.plugins.azure.plugin + +import com.dtolabs.rundeck.core.execution.workflow.steps.FailureReason + +enum AzureFailureReason implements FailureReason{ + + KeyStorage + +} \ No newline at end of file diff --git a/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSource.groovy b/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSource.groovy index 61360b0..08c54ef 100644 --- a/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSource.groovy +++ b/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSource.groovy @@ -6,10 +6,13 @@ import com.dtolabs.rundeck.core.common.NodeEntryImpl import com.dtolabs.rundeck.core.common.NodeSetImpl import com.dtolabs.rundeck.core.resources.ResourceModelSource import com.dtolabs.rundeck.core.resources.ResourceModelSourceException +import com.dtolabs.rundeck.core.storage.keys.KeyStorageTree import com.rundeck.plugins.azure.azure.AzureManager import com.rundeck.plugins.azure.azure.AzureManagerBuilder import com.rundeck.plugins.azure.azure.AzureNode import com.rundeck.plugins.azure.azure.AzureNodeMapper +import com.rundeck.plugins.azure.util.AzurePluginUtil +import org.rundeck.app.spi.Services /** * Created by luistoledo on 11/6/17. @@ -18,9 +21,12 @@ class AzureResourceModelSource implements ResourceModelSource { private Properties configuration; private AzureManager manager; + Services services - AzureResourceModelSource(Properties configuration) { + + AzureResourceModelSource(Properties configuration, Services services) { this.configuration = configuration + this.services = services } void setAzureManager(AzureManager manager){ @@ -42,6 +48,12 @@ class AzureResourceModelSource implements ResourceModelSource { String tagValue=configuration.getProperty(AzureResourceModelSourceFactory.TAG_VALUE) String extraMapping=configuration.getProperty(AzureResourceModelSourceFactory.EXTRA_MAPPING) boolean useAzureTags=Boolean.parseBoolean(configuration.getProperty(AzureResourceModelSourceFactory.USE_AZURE_TAGS)) + String keyStoragePath=configuration.getProperty(AzureResourceModelSourceFactory.KEY_STORAGE_PATH) + + if(keyStoragePath){ + KeyStorageTree keyStorage = services.getService(KeyStorageTree.class) + key = AzurePluginUtil.getPasswordFromKeyStorage(keyStoragePath, keyStorage) + } boolean debug=Boolean.parseBoolean(configuration.getProperty(AzureResourceModelSourceFactory.DEBUG)) diff --git a/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceFactory.groovy b/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceFactory.groovy index 9ffc653..8099970 100644 --- a/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceFactory.groovy +++ b/src/main/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceFactory.groovy @@ -12,6 +12,8 @@ import com.dtolabs.rundeck.plugins.ServiceNameConstants import com.dtolabs.rundeck.plugins.descriptions.PluginDescription import com.dtolabs.rundeck.plugins.util.DescriptionBuilder import com.rundeck.plugins.azure.util.AzurePluginUtil +import org.rundeck.app.spi.Services + /** * Created by luistoledo on 11/3/17. */ @@ -31,6 +33,8 @@ class AzureResourceModelSourceFactory implements ResourceModelSourceFactory,Desc public static final String TENANT = "tenant" public static final String SUBSCRIPTION_ID = "subscriptionId" public static final String KEY = "key" + public static final String KEY_STORAGE_PATH = "keyStoragePath" + public static final String PFX_CERTIFICATE_PATH = "pfxCertificatePath" public static final String PFX_CERTIFICATE_PASSWORD = "pfxCertificatePassword" @@ -49,6 +53,8 @@ class AzureResourceModelSourceFactory implements ResourceModelSourceFactory,Desc final static Map renderingOptionsAuthentication = AzurePluginUtil.getRenderOpt("Credentials",false) final static Map renderingOptionsAuthenticationPassword = AzurePluginUtil.getRenderOpt("Credentials",false, true) final static Map renderingOptionsConfig = AzurePluginUtil.getRenderOpt("Configuration",false) + final static Map renderingOptionsAuthenticationStorage = AzurePluginUtil.getRenderOpt("Credentials",false, false, true) + AzureResourceModelSourceFactory(Framework framework) { this.framework = framework @@ -68,6 +74,8 @@ class AzureResourceModelSourceFactory implements ResourceModelSourceFactory,Desc null,null,null, renderingOptionsAuthentication)) .property(PropertyUtil.string(KEY, "Key", "Azure Access Key.", false, null,null,null, renderingOptionsAuthenticationPassword)) + .property(PropertyUtil.string(KEY_STORAGE_PATH, "Key Storage Path", "Azure Access Key from Rundeck storage path.", false, + null,null,null, renderingOptionsAuthenticationStorage)) .property(PropertyUtil.string(PFX_CERTIFICATE_PATH, "Certificate Path", "Azure certificate file path.", false, null,null,null, renderingOptionsAuthentication)) .property(PropertyUtil.string(PFX_CERTIFICATE_PASSWORD, "Certificate Password", "Azure certificate Password.", false, @@ -100,7 +108,12 @@ class AzureResourceModelSourceFactory implements ResourceModelSourceFactory,Desc @Override ResourceModelSource createResourceModelSource(Properties configuration) throws ConfigurationException { - final AzureResourceModelSource resource = new AzureResourceModelSource(configuration) + return null + } + + @Override + ResourceModelSource createResourceModelSource(Services services, Properties configuration) throws ConfigurationException { + final AzureResourceModelSource resource = new AzureResourceModelSource(configuration, services) return resource } diff --git a/src/main/groovy/com/rundeck/plugins/azure/util/AzurePluginUtil.groovy b/src/main/groovy/com/rundeck/plugins/azure/util/AzurePluginUtil.groovy index 4bb9f43..c3724ab 100644 --- a/src/main/groovy/com/rundeck/plugins/azure/util/AzurePluginUtil.groovy +++ b/src/main/groovy/com/rundeck/plugins/azure/util/AzurePluginUtil.groovy @@ -1,13 +1,15 @@ package com.rundeck.plugins.azure.util +import com.dtolabs.rundeck.core.execution.workflow.steps.StepException import com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants import com.dtolabs.rundeck.core.storage.ResourceMeta +import com.dtolabs.rundeck.core.storage.StorageTree import com.dtolabs.rundeck.plugins.step.PluginStepContext import com.microsoft.azure.management.compute.DataDisk -import com.microsoft.azure.management.compute.DiskInstanceView -import com.microsoft.azure.management.compute.InstanceViewStatus import com.microsoft.azure.management.compute.VirtualMachine import com.microsoft.azure.management.compute.VirtualMachineExtension +import com.rundeck.plugins.azure.plugin.AzureFailureReason +import groovy.transform.CompileStatic /** * Created by luistoledo on 11/6/17. @@ -200,6 +202,20 @@ class AzurePluginUtil { } + static String getPasswordFromKeyStorage(String path, StorageTree storage) { + try{ + ResourceMeta contents = storage.getResource(path).getContents() + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream() + contents.writeContent(byteArrayOutputStream) + String password = new String(byteArrayOutputStream.toByteArray()) + + return password + }catch(Exception e){ + throw new StepException("error accessing ${path}: ${e.message}", AzureFailureReason.KeyStorage) + } + + } + static void printMessage(String message, boolean debug, String level){ diff --git a/src/test/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceSpec.groovy b/src/test/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceSpec.groovy index 95579c8..2983ae6 100644 --- a/src/test/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceSpec.groovy +++ b/src/test/groovy/com/rundeck/plugins/azure/plugin/AzureResourceModelSourceSpec.groovy @@ -5,9 +5,13 @@ import com.dtolabs.rundeck.core.common.INodeSet import com.dtolabs.rundeck.core.resources.ResourceModelSourceException import com.dtolabs.rundeck.core.resources.format.ResourceFormatParser import com.dtolabs.rundeck.core.resources.format.ResourceFormatParserService +import com.dtolabs.rundeck.core.storage.ResourceMeta +import com.dtolabs.rundeck.core.storage.keys.KeyStorageTree import com.microsoft.azure.management.Azure import com.rundeck.plugins.azure.azure.AzureManager import com.rundeck.plugins.azure.azure.AzureNode +import org.rundeck.app.spi.Services +import org.rundeck.storage.api.Resource import spock.lang.Specification /** @@ -23,8 +27,9 @@ class AzureResourceModelSourceSpec extends Specification{ azureManager.setAzure(azure) Properties configuration = [client:"client123",tenant:"tenant123",key:"key123",subscriptionId:"subscriptionId123"] + Services services = getServices() - def azureResource = new AzureResourceModelSource(configuration) + def azureResource = new AzureResourceModelSource(configuration, services) azureResource.setAzureManager(azureManager) AzureNode test = new AzureNode() @@ -51,8 +56,9 @@ class AzureResourceModelSourceSpec extends Specification{ azureManager.setAzure(azure) Properties configuration = [client:"1234"] + Services services = getServices() - def azureResource = new AzureResourceModelSource(configuration) + def azureResource = new AzureResourceModelSource(configuration, services) azureResource.setAzureManager(azureManager) AzureNode test = new AzureNode() @@ -73,10 +79,11 @@ class AzureResourceModelSourceSpec extends Specification{ def azureManager = Mock(AzureManager) def azure = GroovyMock(Azure) azureManager.setAzure(azure) + Services services = getServices() Properties configuration = [client:"client123",tenant:"tenant123",key:"key123",subscriptionId:"subscriptionId123"] - def azureResource = new AzureResourceModelSource(configuration) + def azureResource = new AzureResourceModelSource(configuration, services) when: azureResource.getNodes() @@ -92,10 +99,11 @@ class AzureResourceModelSourceSpec extends Specification{ def azureManager = Mock(AzureManager) def azure = GroovyMock(Azure) azureManager.setAzure(azure) + Services services = getServices() Properties configuration = [client:"client123",tenant:"tenant123",subscriptionId:"subscriptionId123"] - def azureResource = new AzureResourceModelSource(configuration) + def azureResource = new AzureResourceModelSource(configuration, services) azureResource.setAzureManager(azureManager) when: @@ -106,6 +114,54 @@ class AzureResourceModelSourceSpec extends Specification{ } + def "retrieve resource success using key storage"(){ + given: + + def azureManager = Mock(AzureManager) + def azure = GroovyMock(Azure) + azureManager.setAzure(azure) + + Services services = getServices() + + Properties configuration = [client:"client123",tenant:"tenant123",keyStoragePath:"keys/azure.key",subscriptionId:"subscriptionId123"] + + def azureResource = new AzureResourceModelSource(configuration, services) + azureResource.setAzureManager(azureManager) + + AzureNode test = new AzureNode() + test.name="test" + + AzureNode test2 = new AzureNode() + test2.name="test2" + def vmList = [test,test2] + + when: + def result = azureResource.getNodes() + + then: + 1 * azureManager.listVms() >> vmList + result.size()==vmList.size() + + } + + + Services getServices(){ + def storageTree = Mock(KeyStorageTree) + storageTree.getResource(_) >> Mock(Resource) { + getContents() >> Mock(ResourceMeta) { + writeContent(_) >> { args -> + args[0].write('password'.bytes) + return 6L + } + } + } + + Services services = Mock(Services){ + getService(KeyStorageTree.class) >> storageTree + } + return services + } + } From 2292272bc8a233170753b4cf3d05a188069642de Mon Sep 17 00:00:00 2001 From: Luis Toledo Date: Fri, 6 Aug 2021 16:04:58 -0400 Subject: [PATCH 2/2] upgrade rundeck core lib --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dfc9b59..364edfe 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ configurations { dependencies { compile 'org.codehaus.groovy:groovy-all:2.3.11' testCompile group: 'junit', name: 'junit', version: '4.12' - compile group: 'org.rundeck', name: 'rundeck-core', version: '2.10.0' + compile group: 'org.rundeck', name: 'rundeck-core', version: '3.3.+' pluginLibs (group: 'com.microsoft.azure', name: 'azure', version: '1.3.0'){ exclude group: "com.fasterxml.jackson.core" }