Skip to content

Commit

Permalink
Add RecourceModelSource spec
Browse files Browse the repository at this point in the history
  • Loading branch information
qualman committed May 13, 2022
1 parent cc6ec53 commit bdff7fd
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 25 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ dependencies {
testCompile "org.codehaus.groovy:groovy-all:2.3.7"
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
testCompile "cglib:cglib-nodep:2.2.2"
testCompile 'org.objenesis:objenesis:3.1'
}

// task to copy plugin libs to output/lib dir
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,10 @@ static String getPasswordFromKeyStorage(String path, KeyStorageTree storage) {
String key = new String(storage.readPassword(path));
return key;
}catch (Exception e){
throw StorageException.readException(PathUtil.asPath(path), "error accessing key storage: ${e.message}");
throw StorageException.readException(
PathUtil.asPath(path),
"error accessing key storage at " + path + ": " + e.getMessage()
);
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.dtolabs.rundeck.plugin.resources.ec2

import com.dtolabs.rundeck.core.common.Framework
import com.dtolabs.rundeck.core.common.IRundeckProject
import com.dtolabs.rundeck.core.common.ProjectManager
import com.dtolabs.rundeck.core.storage.keys.KeyStorageTree
import org.rundeck.app.spi.Services
import spock.lang.Specification

class EC2ResourceModelSourceSpec extends Specification {
def "user configured access credentials prefer key storage"() {
given: "a user's plugin config"
//Define good and bad keys and paths
def validAccessKey = "validAccessKey"
def validSecretKey = "validSecretKey"
def validKeyPath = "keys/validKeyPath"
def badPath = "keys/badPath"
def badPass = "myNetflixPassword"

// Mock services and Key Storage return of passwords
def serviceWithGoodPass = mockServicesWithPassword(validKeyPath, validSecretKey)
def serviceWithBadPass = mockServicesWithPassword(badPath, badPass)

// Create a default config object (these are the settings the user would setup via the Plugin UI)
def defaultConfig = createDefaultConfig()
defaultConfig.setProperty(EC2ResourceModelSourceFactory.ACCESS_KEY, validAccessKey)

// Create a working config from the defaults
def workingConfig = new Properties()
workingConfig.putAll(defaultConfig)
// Send a bad key to ensure key path takes precedence and succeeds
workingConfig.setProperty(EC2ResourceModelSourceFactory.SECRET_KEY, badPass)
workingConfig.setProperty(EC2ResourceModelSourceFactory.SECRET_KEY_STORAGE_PATH, validKeyPath)

// Create a failing config from the defaults
def failingConfig = new Properties()
failingConfig.putAll(defaultConfig)
// Send a valid key to ensure storage path takes precedence and fails
failingConfig.setProperty(EC2ResourceModelSourceFactory.SECRET_KEY, validSecretKey)
failingConfig.setProperty(EC2ResourceModelSourceFactory.SECRET_KEY_STORAGE_PATH, badPath)

// Create objects using actual ResourceModelSource and Factory
def workingRms = ec2ResourceModelSource(serviceWithGoodPass, workingConfig)
def failingRms = ec2ResourceModelSource(serviceWithBadPass, failingConfig)

when: "we check the access keys of the resource model source objects"
// Instead of using getNodes, which would all be highly mocked, just check that we got as far as setting
// proper credentials right before the point we would call to AWS
def workingRmsPass = workingRms.credentials.getAWSSecretKey()
def failingRmsPass = failingRms.credentials.getAWSSecretKey()

then: "we see that the proper keys from the key storage or the inline key have been derived"
workingRmsPass == validSecretKey
failingRmsPass == badPass
}
//
// Private Methods
//
private def createDefaultConfig() {
def configuration = new Properties()
def assumeRoleArn = "arn:aws:iam::123456789012:role/fake-test-arn"
def endpoint = "ALL_REGIONS"
def pageResults = "100"
def proxyPortStr = "80"
def refreshStr = "30"
def useDefaultMapping = "true"
def runningOnly = "true"

configuration.setProperty(EC2ResourceModelSourceFactory.ROLE_ARN, assumeRoleArn)
configuration.setProperty(EC2ResourceModelSourceFactory.ENDPOINT, endpoint);
configuration.setProperty(EC2ResourceModelSourceFactory.MAX_RESULTS, pageResults);
configuration.setProperty(EC2ResourceModelSourceFactory.HTTP_PROXY_PORT, proxyPortStr);
configuration.setProperty(EC2ResourceModelSourceFactory.REFRESH_INTERVAL, refreshStr);
configuration.setProperty(EC2ResourceModelSourceFactory.USE_DEFAULT_MAPPING, useDefaultMapping)
configuration.setProperty(EC2ResourceModelSourceFactory.RUNNING_ONLY, runningOnly)

return configuration
}

private def ec2ResourceModelSource(Services services, Properties configuration) {
def framework = Mock(Framework)
def factory = new EC2ResourceModelSourceFactory(framework)

return factory.createResourceModelSource(services, configuration)
}

private def mockServicesWithPassword(String path, String password) {
def storageTree = Mock(KeyStorageTree) {
readPassword(path) >> {
return password.bytes
}
}

def services = Mock(Services) {
getService(KeyStorageTree.class) >> storageTree
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,28 +160,6 @@ class InstanceToNodeMapperSpec extends Specification {
'instanceId|tags/Name+"_"+tags/env' | null | 'aninstanceId,bob_PROD'
}

private static Instance mkInstance() {
Instance i = new Instance()
i.withTags(new Tag('Name', 'bob'), new Tag('env', 'PROD'))
i.setInstanceId("aninstanceId")
i.setArchitecture("anarch")
i.setImageId("ami-something")
i.setPlacement(new Placement("us-east-1a"))

def state = new InstanceState()
state.setName(InstanceStateName.Running)
i.setState(state)
i.setPrivateIpAddress('127.0.9.9')
return i
}

private static Image mkImage(){
Image image = new Image()
image.setImageId("ami-something")
image.setName("AMISomething")
return image
}

def "extra mapping image"() {
given:

Expand Down Expand Up @@ -223,8 +201,6 @@ class InstanceToNodeMapperSpec extends Specification {
'imageId+"-"+imageName' | "ami_image"
}



def "extra mapping not calling image list"() {
given:

Expand Down Expand Up @@ -301,4 +277,29 @@ class InstanceToNodeMapperSpec extends Specification {
instances.getNode("aninstanceId").getAttributes().get("region") == "us-east-1"

}

//
// Private Methods
//
private static Instance mkInstance() {
Instance i = new Instance()
i.withTags(new Tag('Name', 'bob'), new Tag('env', 'PROD'))
i.setInstanceId("aninstanceId")
i.setArchitecture("anarch")
i.setImageId("ami-something")
i.setPlacement(new Placement("us-east-1a"))

def state = new InstanceState()
state.setName(InstanceStateName.Running)
i.setState(state)
i.setPrivateIpAddress('127.0.9.9')
return i
}

private static Image mkImage(){
Image image = new Image()
image.setImageId("ami-something")
image.setName("AMISomething")
return image
}
}

0 comments on commit bdff7fd

Please sign in to comment.