Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
feat(provider/dcos): Adding proxy for marathon-client to make use of …
Browse files Browse the repository at this point in the history
…spectator. (spinnaker#1960)
  • Loading branch information
Trevin Teacutter authored and Michael Tweten committed Nov 10, 2017
1 parent 51b96ca commit 7ccc85b
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import mesosphere.dcos.client.DCOSClient

import java.util.concurrent.ConcurrentHashMap

import static java.lang.reflect.Proxy.newProxyInstance

class DcosClientProvider {

private final Map<String, DCOS> dcosClients = new ConcurrentHashMap<>()
Expand All @@ -37,13 +39,23 @@ class DcosClientProvider {
DCOS getDcosClient(DcosAccountCredentials credentials, String clusterName) {
def compositeKey = DcosClientCompositeKey.buildFromVerbose(credentials.account, clusterName).get()
def trueCredentials = credentials.getCredentialsByCluster(clusterName)

return dcosClients.computeIfAbsent(compositeKey.toString(), { k -> DCOSClient.getInstance(trueCredentials.dcosUrl, trueCredentials.dcosConfig) })
def clientInterfaces = new Class<?>[1]
clientInterfaces[0] = DCOS.class

return dcosClients.computeIfAbsent(compositeKey.toString(), { k ->
newProxyInstance(DCOS.class.getClassLoader(), [DCOS.class] as Class<?>[],
new DcosSpectatorHandler(DCOSClient.getInstance(trueCredentials.dcosUrl, trueCredentials.dcosConfig),
credentials.account, clusterName, credentials.spectatorRegistry))
})
}

DCOS getDcosClient(DcosClusterCredentials credentials) {
def compositeKey = DcosClientCompositeKey.buildFrom(credentials.account, credentials.cluster).get()

return dcosClients.computeIfAbsent(compositeKey.toString(), { k -> DCOSClient.getInstance(credentials.dcosUrl, credentials.dcosConfig) })
return dcosClients.computeIfAbsent(compositeKey.toString(), { k ->
newProxyInstance(DCOS.class.getClassLoader(), [DCOS.class] as Class<?>[],
new DcosSpectatorHandler(DCOSClient.getInstance(credentials.dcosUrl, credentials.dcosConfig),
credentials.account, credentials.cluster, credentials.spectatorRegistry))
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.netflix.spinnaker.clouddriver.dcos

import com.netflix.spectator.api.Clock
import com.netflix.spectator.api.Registry
import mesosphere.dcos.client.DCOS
import mesosphere.dcos.client.DCOSException

import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.util.concurrent.TimeUnit

class DcosSpectatorHandler implements InvocationHandler {
private final DCOS dcosClient
private final Registry registry
private final Clock clock
private final String accountName
private final String regionName

DcosSpectatorHandler(DCOS dcosClient, String accountName, String regionName, Registry registry) {
this.dcosClient = dcosClient
this.accountName = accountName
this.regionName = regionName
this.clock = registry.clock()
this.registry = registry
}

@Override
Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null
Throwable failure = null
long startTime = clock.monotonicTime()

try {
result = method.invoke(dcosClient, args)
} catch (DCOSException e) {
failure = e.cause
} catch (Exception e) {
failure = e
} finally {
Map<String, String> tags = new HashMap<>()

tags.put("method", method.name)
tags.put("account", accountName)
tags.put("region", regionName)

if (failure == null) {
tags.put("success", "true")
} else {
tags.put("success", "false")
tags.put("reason", failure.getClass().getSimpleName() + ": " + failure.getMessage())
}

registry.timer(registry.createId("dcos.api", tags))
.record(clock.monotonicTime() - startTime, TimeUnit.NANOSECONDS)
}

if (failure != null) {
throw new Throwable(method.name, failure)
} else {
return result
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.netflix.spinnaker.clouddriver.dcos.security

import com.fasterxml.jackson.annotation.JsonIgnore
import com.netflix.spectator.api.Registry
import com.netflix.spinnaker.clouddriver.dcos.cache.Keys
import com.netflix.spinnaker.clouddriver.dcos.deploy.util.id.MarathonPathId
import com.netflix.spinnaker.clouddriver.security.AccountCredentials
Expand All @@ -39,6 +40,7 @@ class DcosAccountCredentials implements AccountCredentials<DcosCredentialMap> {
final List<String> requiredGroupMembership
final Permissions permissions
final List<DcosRegion> regions
final Registry spectatorRegistry
// Not really a fan of creating this just for use within deck, but it works for now
final List<DcosClusterInfo> dcosClusters

Expand All @@ -51,6 +53,7 @@ class DcosAccountCredentials implements AccountCredentials<DcosCredentialMap> {
List<LinkedDockerRegistryConfiguration> dockerRegistries,
List<String> requiredGroupMembership,
Permissions permissions,
Registry spectatorRegistry,
List<DcosClusterCredentials> clusters) {
this.name = account
this.account = account
Expand All @@ -59,6 +62,7 @@ class DcosAccountCredentials implements AccountCredentials<DcosCredentialMap> {
this.dockerRegistries = dockerRegistries != null ? dockerRegistries : new ArrayList<>()
this.requiredGroupMembership = requiredGroupMembership
this.permissions = permissions
this.spectatorRegistry = spectatorRegistry
this.dcosClusterCredentials = new DcosCredentialMap(clusters)
this.dcosClusters = clusters.collect({ new DcosClusterInfo(it.name, it.dcosUrl, it.dockerRegistries) })
this.regions = clusters.collect({ new DcosRegion(it.name) })
Expand Down Expand Up @@ -91,6 +95,7 @@ class DcosAccountCredentials implements AccountCredentials<DcosCredentialMap> {
private List<LinkedDockerRegistryConfiguration> dockerRegistries
private List<String> requiredGroupMembership
private Permissions permissions
private Registry spectatorRegistry
private List<DcosClusterCredentials> clusterCredentials

Builder account(String account) {
Expand Down Expand Up @@ -131,6 +136,11 @@ class DcosAccountCredentials implements AccountCredentials<DcosCredentialMap> {
return this
}

Builder spectatorRegistry(Registry spectatorRegistry) {
this.spectatorRegistry = spectatorRegistry
return this
}

DcosAccountCredentials build() {
if (!account) {
throw new IllegalArgumentException("Account name for DC/OS provider is missing.")
Expand All @@ -153,7 +163,7 @@ class DcosAccountCredentials implements AccountCredentials<DcosCredentialMap> {

requiredGroupMembership = requiredGroupMembership ? Collections.unmodifiableList(requiredGroupMembership) : []

new DcosAccountCredentials(account, environment, accountType, dockerRegistries, requiredGroupMembership, permissions, clusterCredentials)
new DcosAccountCredentials(account, environment, accountType, dockerRegistries, requiredGroupMembership, permissions, spectatorRegistry, clusterCredentials)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.netflix.spinnaker.clouddriver.dcos.security

import com.netflix.spectator.api.Registry
import com.netflix.spinnaker.clouddriver.dcos.DcosClientCompositeKey
import com.netflix.spinnaker.clouddriver.dcos.DcosConfigurationProperties
import mesosphere.dcos.client.Config
Expand All @@ -30,6 +31,7 @@ class DcosClusterCredentials {
final String secretStore
final List<DcosConfigurationProperties.LinkedDockerRegistryConfiguration> dockerRegistries
final Config dcosConfig
final Registry spectatorRegistry

private DcosClusterCredentials(Builder builder) {
name = builder.key.cluster
Expand All @@ -39,6 +41,7 @@ class DcosClusterCredentials {
secretStore = builder.secretStore ? builder.secretStore : DEFAULT_SECRET_STORE
dockerRegistries = builder.dockerRegistries
dcosConfig = builder.dcosConfig
spectatorRegistry = builder.spectatorRegistry
}

public static Builder builder() {
Expand All @@ -51,6 +54,7 @@ class DcosClusterCredentials {
private String secretStore
private List<DcosConfigurationProperties.LinkedDockerRegistryConfiguration> dockerRegistries
private Config dcosConfig
private Registry spectatorRegistry

public Builder key(DcosClientCompositeKey key) {
this.key = key
Expand All @@ -77,6 +81,12 @@ class DcosClusterCredentials {
this
}


public Builder spectatorRegistry(Registry spectatorRegistry) {
this.spectatorRegistry = spectatorRegistry
this
}

public DcosClusterCredentials build() {
return new DcosClusterCredentials(this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.netflix.spinnaker.clouddriver.dcos.security

import com.netflix.spectator.api.Registry
import com.netflix.spinnaker.cats.module.CatsModule
import com.netflix.spinnaker.cats.provider.ProviderSynchronizerTypeWrapper
import com.netflix.spinnaker.clouddriver.dcos.DcosClientCompositeKey
Expand All @@ -29,6 +30,7 @@ import groovy.util.logging.Slf4j
import mesosphere.dcos.client.DCOS
import mesosphere.dcos.client.DCOSException
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
Expand All @@ -41,6 +43,8 @@ import org.springframework.context.annotation.Scope
class DcosCredentialsInitializer implements CredentialsInitializerSynchronizable {
private final static LOGGER = LoggerFactory.getLogger(DcosCredentialsInitializer)

@Autowired Registry spectatorRegistry

@Bean
List<? extends DcosAccountCredentials> dcosCredentials(String clouddriverUserAgentApplicationName,
DcosConfigurationProperties dcosConfigurationProperties,
Expand Down Expand Up @@ -103,7 +107,8 @@ class DcosCredentialsInitializer implements CredentialsInitializerSynchronizable

DcosClusterCredentials clusterCredentials = DcosClusterCredentials.builder().key(key.get()).dcosUrl(cluster.dcosUrl)
.secretStore(cluster.secretStore).dockerRegistries(dockerRegistries)
.dcosConfig(DcosConfigurationProperties.buildConfig(account, cluster, clusterConfig)).build()
.dcosConfig(DcosConfigurationProperties.buildConfig(account, cluster, clusterConfig))
.spectatorRegistry(spectatorRegistry).build()

DCOS client = clientProvider.getDcosClient(clusterCredentials)
try {
Expand All @@ -118,7 +123,7 @@ class DcosCredentialsInitializer implements CredentialsInitializerSynchronizable
DcosAccountCredentials dcosCredentials = DcosAccountCredentials.builder().account(account.name).environment(account.environment)
.accountType(account.accountType).dockerRegistries(account.dockerRegistries)
.requiredGroupMembership(account.requiredGroupMembership).clusters(allAccountClusterCredentials)
.permissions(account.permissions.build()).build()
.permissions(account.permissions.build()).spectatorRegistry(spectatorRegistry).build()

// Note: The MapBackedAccountCredentialsRepository doesn't actually use the key for anything currently.
accountCredentialsRepository.save(dcosCredentials.name, dcosCredentials)
Expand Down

0 comments on commit 7ccc85b

Please sign in to comment.