Skip to content

Commit

Permalink
feat(provider/oraclebmcs): Server group service, caching agent and cl…
Browse files Browse the repository at this point in the history
…uster provider (#1574)

Oracle BMCS does not have cloud native support for server groups yet. So we've (@hhexo) built an implementation
around our object storage service for the time being.
  • Loading branch information
simonlord authored and Matt Duftler committed Apr 20, 2017
1 parent b0ccda5 commit 4063e18
Show file tree
Hide file tree
Showing 15 changed files with 1,557 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Keys {

static enum Namespace {

SERVER_GROUPS,
NETWORKS,
SUBNETS,
IMAGES,
Expand Down Expand Up @@ -76,6 +77,19 @@ class Keys {
account: parts[4]
]
break
case Namespace.SERVER_GROUPS.ns:
def names = Names.parseName(parts[5])
result << [
application: names.app,
cluster : parts[2],
account : parts[3],
region : parts[4],
stack : names.stack,
detail : names.detail,
serverGroup: parts[5],
name : parts[5]
]
break
case Namespace.IMAGES.ns:
result << [
account: parts[2],
Expand Down Expand Up @@ -132,4 +146,9 @@ class Keys {
"$OracleBMCSCloudProvider.ID:${Namespace.SUBNETS}:${subnetId}:${region}:${account}"
}

static String getServerGroupKey(String account, String region, String serverGroupName) {
Names names = Names.parseName(serverGroupName)
"$OracleBMCSCloudProvider.ID:${Namespace.SERVER_GROUPS}:${names.cluster}:${account}:${region}:${serverGroupName}"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2017 Oracle America, Inc.
*
* The contents of this file are subject to the Apache License Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* If a copy of the Apache License Version 2.0 was not distributed with this file,
* You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html
*/
package com.netflix.spinnaker.clouddriver.oraclebmcs.model

import com.fasterxml.jackson.annotation.JsonIgnore
import com.netflix.spinnaker.clouddriver.model.Cluster
import com.netflix.spinnaker.clouddriver.model.LoadBalancer
import com.netflix.spinnaker.clouddriver.oraclebmcs.OracleBMCSCloudProvider
import groovy.transform.Canonical
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode

@CompileStatic
@EqualsAndHashCode(includes = ["name", "accountName"])
class OracleBMCSCluster {

String name
String accountName
Set<OracleBMCSServerGroup> serverGroups

@JsonIgnore
View getView() {
new View()
}

@Canonical
class View implements Cluster {

final String type = OracleBMCSCloudProvider.ID

String name = OracleBMCSCluster.this.name
String accountName = OracleBMCSCluster.this.accountName
Set<OracleBMCSServerGroup.View> serverGroups = OracleBMCSCluster.this.serverGroups.collect { it.getView() } as Set
Set<LoadBalancer> loadBalancers = [] as Set
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Copyright (c) 2017 Oracle America, Inc.
*
* The contents of this file are subject to the Apache License Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* If a copy of the Apache License Version 2.0 was not distributed with this file,
* You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html
*/
package com.netflix.spinnaker.clouddriver.oraclebmcs.model

import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude
import com.netflix.spinnaker.clouddriver.model.HealthState
import com.netflix.spinnaker.clouddriver.model.Instance
import com.netflix.spinnaker.clouddriver.model.ServerGroup
import com.netflix.spinnaker.clouddriver.oraclebmcs.OracleBMCSCloudProvider
import com.netflix.spinnaker.clouddriver.oraclebmcs.security.OracleBMCSNamedAccountCredentials
import groovy.transform.Canonical

@Canonical
class OracleBMCSServerGroup {

String name
String region
String zone
Set<String> zones = new HashSet<>()
Set<OracleBMCSInstance> instances = []
Map<String, Object> launchConfig = [:]
Set<String> securityGroups = []
Map buildInfo
Boolean disabled = false
Integer targetSize
OracleBMCSNamedAccountCredentials credentials

@JsonIgnore
View getView() {
new View()
}

@JsonInclude(JsonInclude.Include.NON_NULL)
@Canonical
class View implements ServerGroup {

final String type = OracleBMCSCloudProvider.ID
final String cloudProvider = OracleBMCSCloudProvider.ID

String name = OracleBMCSServerGroup.this.name
String region = OracleBMCSServerGroup.this.region
String zone = OracleBMCSServerGroup.this.zone
Set<String> zones = OracleBMCSServerGroup.this.zones
Set<OracleBMCSInstance> instances = OracleBMCSServerGroup.this.instances
Map<String, Object> launchConfig = OracleBMCSServerGroup.this.launchConfig
Set<String> securityGroups = OracleBMCSServerGroup.this.securityGroups
Map buildInfo = OracleBMCSServerGroup.this.buildInfo
Boolean disabled = OracleBMCSServerGroup.this.disabled
ServerGroup.Capacity capacity = new ServerGroup.Capacity(desired: OracleBMCSServerGroup.this.targetSize,
min: OracleBMCSServerGroup.this.targetSize, max: OracleBMCSServerGroup.this.targetSize)

@Override
Boolean isDisabled() { // Because groovy isn't smart enough to generate this method :-(
disabled
}

@Override
Long getCreatedTime() {
launchConfig ? launchConfig.createdTime as Long : null
}

@Override
Set<String> getLoadBalancers() {
return null
}

@Override
ServerGroup.Capacity getCapacity() {
capacity
}

@Override
ServerGroup.ImagesSummary getImagesSummary() {
def bi = OracleBMCSServerGroup.this.buildInfo
return new ServerGroup.ImagesSummary() {

@Override
List<ServerGroup.ImageSummary> getSummaries() {
return [new ServerGroup.ImageSummary() {

String serverGroupName = name
String imageName = launchConfig?.instanceTemplate?.name
String imageId = launchConfig?.imageId

@Override
Map<String, Object> getBuildInfo() {
return bi
}

@Override
Map<String, Object> getImage() {
return launchConfig?.instanceTemplate
}
}]
}
}
}

@Override
ServerGroup.ImageSummary getImageSummary() {
imagesSummary?.summaries?.get(0)
}

@Override
ServerGroup.InstanceCounts getInstanceCounts() {
new ServerGroup.InstanceCounts(
total: instances.size(),
up: filterInstancesByHealthState(instances, HealthState.Up)?.size() ?: 0,
down: filterInstancesByHealthState(instances, HealthState.Down)?.size() ?: 0,
unknown: filterInstancesByHealthState(instances, HealthState.Unknown)?.size() ?: 0,
starting: filterInstancesByHealthState(instances, HealthState.Starting)?.size() ?: 0,
outOfService: filterInstancesByHealthState(instances, HealthState.OutOfService)?.size() ?: 0
)
}

static Collection<Instance> filterInstancesByHealthState(Set<Instance> instances, HealthState healthState) {
instances.findAll { Instance it -> it.getHealthState() == healthState }
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ class OracleBMCSInfrastructureProvider extends AgentSchedulerAware implements Se
final Set<String> defaultCaches = [
Namespace.NETWORKS.ns,
Namespace.SUBNETS.ns,
Namespace.IMAGES.ns
Namespace.IMAGES.ns,
Namespace.INSTANCES.ns,
Namespace.SECURITY_GROUPS.ns,
Namespace.SERVER_GROUPS.ns
].asImmutable()

final Map<String, String> urlMappingTemplates = [:]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2017 Oracle America, Inc.
*
* The contents of this file are subject to the Apache License Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* If a copy of the Apache License Version 2.0 was not distributed with this file,
* You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html
*/
package com.netflix.spinnaker.clouddriver.oraclebmcs.provider.agent

import com.fasterxml.jackson.databind.ObjectMapper
import com.netflix.spinnaker.cats.agent.AgentDataType
import com.netflix.spinnaker.cats.agent.CacheResult
import com.netflix.spinnaker.cats.agent.DefaultCacheResult
import com.netflix.spinnaker.cats.cache.DefaultCacheData
import com.netflix.spinnaker.cats.provider.ProviderCache
import com.netflix.spinnaker.clouddriver.oraclebmcs.cache.Keys
import com.netflix.spinnaker.clouddriver.oraclebmcs.model.OracleBMCSServerGroup
import com.netflix.spinnaker.clouddriver.oraclebmcs.security.OracleBMCSNamedAccountCredentials
import com.netflix.spinnaker.clouddriver.oraclebmcs.service.servergroup.OracleBMCSServerGroupService
import groovy.transform.InheritConstructors
import groovy.util.logging.Slf4j

/**
* A caching agent for Oracle BMCS server groups.
*
* The groups are persisted cloud-side by the OracleBMCSServerGroupService implementation. In this agent we just read
* all server groups that we can see given our credentials.
*
* This may be a slow operation due to the large number of API calls that the service makes.
*
* Created by hhexo on 27/01/2017.
*/
@Slf4j
@InheritConstructors
class OracleBMCSServerGroupCachingAgent extends AbstractOracleBMCSCachingAgent {

final Set<AgentDataType> providedDataTypes = [
AgentDataType.Authority.AUTHORITATIVE.forType(Keys.Namespace.SERVER_GROUPS.ns)
]

private OracleBMCSServerGroupService oracleBMCSServerGroupService

OracleBMCSServerGroupCachingAgent(String clouddriverUserAgentApplicationName, OracleBMCSNamedAccountCredentials credentials, ObjectMapper objectMapper, OracleBMCSServerGroupService oracleBMCSServerGroupService) {
super(objectMapper, credentials, clouddriverUserAgentApplicationName)
this.oracleBMCSServerGroupService = oracleBMCSServerGroupService
}

@Override
CacheResult loadData(ProviderCache providerCache) {
List<OracleBMCSServerGroup> serverGroups = this.oracleBMCSServerGroupService.listAllServerGroups(this.credentials)
return buildCacheResults(serverGroups)
}

CacheResult buildCacheResults(List<OracleBMCSServerGroup> serverGroups) {
log.info("Describing items in $agentType")
def data = serverGroups.collect { OracleBMCSServerGroup sg ->
// Don't cache credentials, so save them and restore them later
def creds = sg.credentials
sg.credentials = null
Map<String, Object> attributes = objectMapper.convertValue(sg, ATTRIBUTES)
sg.credentials = creds
new DefaultCacheData(
Keys.getServerGroupKey(this.credentials.name, credentials.region, sg.name),
attributes,
[:]
)
}

def cacheData = [(Keys.Namespace.SERVER_GROUPS.ns): data]
log.info("Caching ${data.size()} items in ${agentType}")
return new DefaultCacheResult(cacheData, [:])
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.netflix.spinnaker.clouddriver.oraclebmcs.OracleBMCSConfiguration
import com.netflix.spinnaker.clouddriver.oraclebmcs.provider.OracleBMCSInfrastructureProvider
import com.netflix.spinnaker.clouddriver.oraclebmcs.provider.agent.*
import com.netflix.spinnaker.clouddriver.oraclebmcs.security.OracleBMCSNamedAccountCredentials
import com.netflix.spinnaker.clouddriver.oraclebmcs.service.servergroup.OracleBMCSServerGroupService
import com.netflix.spinnaker.clouddriver.security.AccountCredentialsRepository
import com.netflix.spinnaker.clouddriver.security.ProviderUtils
import org.springframework.beans.factory.config.ConfigurableBeanFactory
Expand All @@ -35,15 +36,17 @@ class OracleBMCSInfrastructureProviderConfig {
OracleBMCSInfrastructureProvider oracleBMCSInfrastructureProvider(String clouddriverUserAgentApplicationName,
AccountCredentialsRepository accountCredentialsRepository,
ObjectMapper objectMapper,
Registry registry) {
Registry registry,
OracleBMCSServerGroupService oracleBMCSServerGroupService) {
def oracleBMCSInfrastructureProvider =
new OracleBMCSInfrastructureProvider(Collections.newSetFromMap(new ConcurrentHashMap<Agent, Boolean>()))

synchronizeOracleBMCSInfrastructureProvider(clouddriverUserAgentApplicationName,
oracleBMCSInfrastructureProvider,
accountCredentialsRepository,
objectMapper,
registry
registry,
oracleBMCSServerGroupService
)

return oracleBMCSInfrastructureProvider
Expand All @@ -55,6 +58,7 @@ class OracleBMCSInfrastructureProviderConfig {
}

class OracleBMCSInfrastructureProviderSynchronizerTypeWrapper implements ProviderSynchronizerTypeWrapper {

@Override
Class getSynchronizerType() {
return OracleBMCSInfrastructureProviderSynchronizer
Expand All @@ -70,7 +74,8 @@ class OracleBMCSInfrastructureProviderConfig {
OracleBMCSInfrastructureProvider oracleBMCSInfrastructureProvider,
AccountCredentialsRepository accountCredentialsRepository,
ObjectMapper objectMapper,
Registry registry) {
Registry registry,
OracleBMCSServerGroupService oracleBMCSServerGroupService) {
def scheduledAccounts = ProviderUtils.getScheduledAccounts(oracleBMCSInfrastructureProvider)
def allAccounts = ProviderUtils.buildThreadSafeSetOfAccounts(accountCredentialsRepository,
OracleBMCSNamedAccountCredentials)
Expand Down Expand Up @@ -98,6 +103,11 @@ class OracleBMCSInfrastructureProviderConfig {
credentials,
objectMapper)

newlyAddedAgents << new OracleBMCSServerGroupCachingAgent(clouddriverUserAgentApplicationName,
credentials,
objectMapper,
oracleBMCSServerGroupService)

newlyAddedAgents << new OracleBMCSImageCachingAgent(clouddriverUserAgentApplicationName,
credentials,
objectMapper)
Expand Down
Loading

0 comments on commit 4063e18

Please sign in to comment.