Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial titan integration #8

Merged
merged 24 commits into from
Sep 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2c1e7e7
Initial commit
Jul 1, 2015
37511ce
Fixing the gradle project dependencies
Jul 1, 2015
f41804c
Merge branch 'master' into titan-integration
Jul 1, 2015
4c6a6f1
Fixing the compilation errors
Jul 1, 2015
fb81d43
Merge branch 'master' into titan-integration
Jul 1, 2015
678602a
Fixing the compilation errors
Jul 1, 2015
51062a8
Incorporating the pull request review comments
Jul 6, 2015
b87176a
Merge branch 'master' into titan-integration
Jul 6, 2015
323bed0
Merge branch 'master' into titan-integration
Jul 28, 2015
819fc04
Upgrading titan-client to use the mocked titan client implementation
Jul 29, 2015
b1822a9
Making the titan module run successfully
Aug 1, 2015
9b078dd
Adding deploy operation for titan with fixes for ClusterCachingAgent,…
Aug 11, 2015
3d50d18
Adding titan destroy server group and resize server group operations
Aug 28, 2015
ee37fe8
Merge branch 'master' into titan-integration
Sep 16, 2015
42b6f58
Merge branch 'master' into titan-integration
Sep 16, 2015
77fa20b
Fixing the compilation failure
Sep 16, 2015
a3c0a59
Implementing additional interface methods
Sep 17, 2015
8833366
Adding @Component annotation to the titan converter and validator
Sep 18, 2015
f7c0ef3
Incorporating latest titan-client with calypso bulk read APIs. Also, …
Sep 22, 2015
510c5d8
Changing the titan destroy server group description and titan deploy …
Sep 22, 2015
172c286
Removing the subnetType from the titan deploy description
Sep 22, 2015
e63ea53
Merge branch 'master' into titan-integration
Sep 22, 2015
13fc8ad
Reverting the BasicAmazonDeployHandler to master HEAD version
Sep 22, 2015
eabdce4
Using the Keys class from cats module instead of oort-aws
Sep 22, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cats/cats-core/cats-core.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies {
compile spinnaker.dependency("frigga")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.cats.cache

import com.netflix.frigga.Names
import groovy.transform.CompileStatic

/**
* @author sthadeshwar
*/
@CompileStatic
class Keys {

static enum Namespace {
IMAGES,
NAMED_IMAGES,
SERVER_GROUPS,
INSTANCES,
LAUNCH_CONFIGS,
LOAD_BALANCERS,
CLUSTERS,
APPLICATIONS,
HEALTH,
ON_DEMAND,
RESERVATION_REPORTS

final String ns

private Namespace() {
def parts = name().split('_')

ns = parts.tail().inject(new StringBuilder(parts.head().toLowerCase())) { val, next -> val.append(next.charAt(0)).append(next.substring(1).toLowerCase()) }
}

String toString() {
ns
}
}

static Map<String, String> parse(String key) {
def parts = key.split(':')

if (parts.length < 2) {
return null
}

def result = [provider: parts[0], type: parts[1]]

switch (result.type) {
case Namespace.IMAGES.ns:
result << [account: parts[2], region: parts[3], imageId: parts[4]]
break
case Namespace.NAMED_IMAGES.ns:
result << [account: parts[2], imageName: parts[3]]
break
case Namespace.SERVER_GROUPS.ns:
def names = Names.parseName(parts[5])
result << [application: names.app.toLowerCase(), cluster: parts[2], account: parts[3], region: parts[4], serverGroup: parts[5], stack: names.stack, detail: names.detail, sequence: names.sequence?.toString()]
break
case Namespace.INSTANCES.ns:
result << [account: parts[2], region: parts[3], instanceId: parts[4]]
break
case Namespace.LAUNCH_CONFIGS.ns:
def names = Names.parseName(parts[4])
result << [account: parts[2], region: parts[3], launchConfig: parts[4], application: names.app?.toLowerCase(), stack: names.stack]
break
case Namespace.LOAD_BALANCERS.ns:
def names = Names.parseName(parts[4])
result << [account: parts[2], region: parts[3], loadBalancer: parts[4], vpcId: parts.length > 5 ? parts[5] : null, application: names.app?.toLowerCase(), stack: names.stack, detail: names.detail]
break
case Namespace.CLUSTERS.ns:
def names = Names.parseName(parts[4])
result << [application: parts[2].toLowerCase(), account: parts[3], cluster: parts[4], stack: names.stack, detail: names.detail]
break
case Namespace.APPLICATIONS.ns:
result << [application: parts[2].toLowerCase()]
break
case Namespace.HEALTH.ns:
result << [instanceId: parts[2], account: parts[3], region: parts[4], provider: parts[5]]
break
default:
return null
break
}

result
}

static String getImageKey(String provider, String imageId, String account, String region) {
"${provider}:${Namespace.IMAGES}:${account}:${region}:${imageId}"
}

static String getNamedImageKey(String provider, String account, String imageName) {
"${provider}:${Namespace.NAMED_IMAGES}:${account}:${imageName}"
}

static String getServerGroupKey(String provider, String autoScalingGroupName, String account, String region) {
Names names = Names.parseName(autoScalingGroupName)
"${provider}:${Namespace.SERVER_GROUPS}:${names.cluster}:${account}:${region}:${names.group}"
}

static String getInstanceKey(String provider, String instanceId, String account, String region) {
"${provider}:${Namespace.INSTANCES}:${account}:${region}:${instanceId}"
}

static String getLaunchConfigKey(String provider, String launchConfigName, String account, String region) {
"${provider}:${Namespace.LAUNCH_CONFIGS}:${account}:${region}:${launchConfigName}"
}

static String getLoadBalancerKey(String provider, String loadBalancerName, String account, String region, String vpcId) {
"${provider}:${Namespace.LOAD_BALANCERS}:${account}:${region}:${loadBalancerName}${vpcId ? ':' + vpcId : ''}"
}

static String getClusterKey(String provider, String clusterName, String application, String account) {
"${provider}:${Namespace.CLUSTERS}:${application.toLowerCase()}:${account}:${clusterName}"
}

static String getApplicationKey(String provider, String application) {
"${provider}:${Namespace.APPLICATIONS}:${application.toLowerCase()}"
}

static String getInstanceHealthKey(String provider, String instanceId, String account, String region, String healthProvider) {
"${provider}:${Namespace.HEALTH}:${instanceId}:${account}:${region}:${healthProvider}"
}
}
7 changes: 7 additions & 0 deletions clouddriver-titan/clouddriver-titan.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencies {
compile project(":clouddriver-core")
compile spinnaker.dependency('amos')
compile spinnaker.dependency('bootActuator')
compile spinnaker.dependency('bootWeb')
compile ('com.netflix:titan-client:0.24')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.titan
import com.netflix.spinnaker.clouddriver.titan.credentials.NetflixTitanCredentials
import com.netflix.titanclient.TitanClient
import groovy.transform.Canonical

/**
* @author sthadeshwar
*/
class TitanClientProvider {

private final List<TitanClientHolder> titanClientHolders

TitanClientProvider(List<TitanClientHolder> titanClientHolders) {
this.titanClientHolders = titanClientHolders
}

TitanClient getTitanClient(NetflixTitanCredentials account, String region) {
TitanClientHolder titanClientHolder = titanClientHolders.find { it.account == account.name && it.region == region }
if (!titanClientHolder) {
throw new IllegalArgumentException("No titan client registered for account ${account.name} and region ${region}")
}
titanClientHolder.titanClient
}

@Canonical
static class TitanClientHolder {
final String account
final String region
final TitanClient titanClient
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.titan

import com.netflix.spinnaker.clouddriver.core.CloudProvider
import org.springframework.stereotype.Component

import java.lang.annotation.Annotation

/**
* @author sthadeshwar
*/
@Component
class TitanCloudProvider implements CloudProvider {
final String id = "titan"
final String displayName = "Titan"
final Class<? extends Annotation> operationAnnotationType = TitanOperation
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.titan
import com.netflix.spinnaker.amos.AccountCredentialsRepository
import com.netflix.spinnaker.clouddriver.titan.credentials.NetflixTitanCredentials
import com.netflix.titanclient.RegionScopedTitanClient
import com.netflix.titanclient.TitanRegion
import groovy.util.logging.Slf4j
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.DependsOn

import javax.annotation.PostConstruct

@Configuration
@ConditionalOnProperty('titan.enabled')
@EnableConfigurationProperties
@ComponentScan('com.netflix.spinnaker.clouddriver.titan')
@Slf4j
class TitanConfiguration {

@PostConstruct
void init() {
log.info("TitanConfiguration is enabled")
}

@Bean
@ConfigurationProperties("titan")
TitanCredentialsConfig titanCredentialsConfig() {
new TitanCredentialsConfig()
}

@Bean(name = "netflixTitanCredentials")
List<NetflixTitanCredentials> netflixTitanCredentials(TitanCredentialsConfig titanCredentialsConfig,
AccountCredentialsRepository repository) {
List<NetflixTitanCredentials> accounts = new ArrayList<>()
for (TitanCredentialsConfig.Account account in titanCredentialsConfig.accounts) {
List<TitanRegion> regions = account.regions.collect { new TitanRegion(it.name, account.name, it.endpoint, it.calypsoEndpoint) }
NetflixTitanCredentials credentials = new NetflixTitanCredentials(account.name, regions)
accounts.add(credentials)
repository.save(account.name, credentials)
}
return accounts
}

@Bean
@DependsOn("netflixTitanCredentials")
TitanClientProvider titanClientProvider(@Value('#{netflixTitanCredentials}') List<NetflixTitanCredentials> netflixTitanCredentials) {
List<TitanClientProvider.TitanClientHolder> titanClientHolders = []
netflixTitanCredentials.each { credentials ->
credentials.regions.each { region ->
titanClientHolders << new TitanClientProvider.TitanClientHolder(
credentials.name, region.name, new RegionScopedTitanClient(region, true)
)
}
}
new TitanClientProvider(titanClientHolders)
}

static class TitanCredentialsConfig {
List<Account> accounts
static class Account {
String name
List<Region> regions
}
static class Region {
String name
String endpoint
String calypsoEndpoint
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.titan

import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target

/**
* @author sthadeshwar
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TitanOperation {
String value()
}
Loading