Upload
spring-io
View
233
Download
1
Tags:
Embed Size (px)
DESCRIPTION
Speaker: Joe Sondow Asgard is a free and open source Grails application built and used by Netflix to deploy code changes and to manage resources in the Amazon cloud at large scale. In this talk we'll delve into how Asgard works, covering topics such as: Open source motivation, presence, and support. Tour of the user interface. Customizing Asgard for your own company. How Netflix philosophies drive Asgard's design. The Netflix Cloud Model. Easy large deployments and fast rollback. Caching the cloud with Groovy. Visual language for the cloud. Publishing a REST API. Mocking AWS for offline testing. Comparison with the AWS Management Console.
Citation preview
Joe Sondow, Netflix
The Grails App that Deploys Netflix to the Cloud
@joesondow
Slides onlinehttp://slideshare.net/joesondow
@joesondow
Who am I?
@joesondow
Who am I?
@joesondow
Who am I?Joe Sondow
@joesondow
Who am I?Joe Sondow
Netflix since 2010
@joesondow
Who am I?Joe Sondow
Netflix since 2010
Asgard lead
@joesondow
Who am I?Joe Sondow
Netflix since 2010
Asgard lead
Grails
@joesondow
Who am I?Joe Sondow
Netflix since 2010
Asgard lead
Grails
jQuery
@joesondow
Why am I here?
Why am I here?
Sell you something
Why am I here?
Sell you something
Discuss business plans
Why am I here?
Sell you something
Discuss business plans
Answer technical questions
Why am I here?
Sell you something
Discuss business plans
Answer technical questions
Be a smaller fish in AWS
Why am I here?
Sell you something
Discuss business plans
Answer technical questions
Be a smaller fish in AWS
Give back to community
Why am I here?
Sell you something
Discuss business plans
Answer technical questions
Be a smaller fish in AWS
Give back to community
Build cloud standards
Why am I here?
Sell you something
Discuss business plans
Answer technical questions
Be a smaller fish in AWS
Give back to community
Build cloud standards
Steal your engineers
Why am I here?
Asgard
Asgard
AsgardScreen shots
AsgardApplication list
AsgardAuto Scaling Group list
AsgardCluster deployment, ready for fast rollback
Asgard
AsgardApplication deployment
AsgardApplication deployment
Cloud management
AsgardApplication deployment
Cloud management
Started 2010
AsgardApplication deployment
Cloud management
Started 2010
Open source June 2012
AsgardApplication deployment
Cloud management
Started 2010
Open source June 2012
http://netflix.github.io
AsgardApplication deployment
Cloud management
Started 2010
Open source June 2012
http://netflix.github.io
100’s of Jira tickets
AsgardApplication deployment
Cloud management
Started 2010
Open source June 2012
http://netflix.github.io
100’s of Jira tickets
Actively developed
Source code and downloadhttps://github.com/Netflix/asgard
User forumhttps://groups.google.com/group/AsgardUsers
Twitter feedhttps://twitter.com/AsgardOSS
The Asgard Showhttps://youtube.com/TheAsgardShow
Open Source, Closed Config
Open Source, Closed ConfigPull company-specific details out of Asgard
Open Source, Closed Config
Open Source, Closed Config
Open Source, Closed ConfigAsgard for Netflix is configured to use company-specific extension points such as standard utility links for instances
Open Source, Closed ConfigOut-of-the-box Asgard installation has no instance utility links
Open Source, Closed Config
link {
// Avoid GStrings here because these Strings are stored dynamic templates for arbitrary server names. String logUrlStart = 'http://${server}:7777' String configUrlStart = 'http://${server}:9999/AdminConfig' instanceLinkGroupingsToLinkTemplateLists = [ 'Logs': [ new TextLinkTemplate(logUrlStart + '/Admin/list?view=tomcat/catalina.out', 'catalina.out'), new TextLinkTemplate(logUrlStart + '/Admin/list', 'Log File Archive'), new TextLinkTemplate(logUrlStart + '/Admin/threaddumps', 'Thread Dumps'), new TextLinkTemplate(logUrlStart + '/AdminProxy', 'Admin Proxy Info'), new TextLinkTemplate(logUrlStart + '/AdminStatus', 'Admin Proxy Status'), new TextLinkTemplate(logUrlStart + '/GC/index', 'GC Visualization') ], 'Netflix Configuration': [ new TextLinkTemplate(configUrlStart + '/prop.html', 'NetflixConfiguration Properties Console'), new TextLinkTemplate(configUrlStart + '/libs.html', 'Libraries Console'), new TextLinkTemplate(configUrlStart + '/machineProps', 'Machine Readable Properties'), new TextLinkTemplate(configUrlStart + '/webapp/META-‐INF/MANIFEST.MF', 'Manifest'), ] ]}
Netflix specific $ASGARD_HOME/Config.groovy
Open Source, Closed Config
asgardHome = System.getenv('ASGARD_HOME') ?: System.getProperty('ASGARD_HOME') ?: "${System.getProperty('user.home')}/.asgard"
// Locations to search for config files that get merged into the main config.// Config files can either be Java properties files or ConfigSlurper scripts.grails.config.locations = [ "file:${asgardHome}/Config.groovy", 'classpath:sourceVersion.properties']
grails-app/conf/Config.groovy references external configuration file~/.asgard/Config.groovyhttps://github.com/Netflix/asgard/blob/master/grails-app/conf/Config.groovy
Open Source, Closed Config
grails { awsAccounts=["171234567890"] awsAccountNames=["171234567890": "prod"]}secret { accessId="AKOBIWANLANDOLUKEHAN" secretKey="Od0INd/C3P0/R2D2atatTIEFIGHTERdeathstar"}cloud { accountName="prod" publicResourceAccounts=["amazon"]}
External Config.groovy also holds the AWS account credentials, or references for finding them.
Netflix is the world’s leading Internet television network with nearly 38 million members in 40 countries enjoying more than one billion hours of TV shows and movies per month, including original series.
(from http://ir.netflix.com)
Freedom and Responsibility
Freedom and ResponsibilityCorporate culture and the Cloud
Freedom and Responsibility
Freedom and ResponsibilityCloud SOA
Freedom and ResponsibilityCloud SOA
100’s of services
Freedom and ResponsibilityCloud SOA
100’s of services
Small teams
Freedom and ResponsibilityCloud SOA
100’s of services
Small teams
Independent releases
Freedom and ResponsibilityCloud SOA
100’s of services
Small teams
Independent releases
Controlled chaos
Cloud deployment model
Cloud deployment modelApplications and Clusters
Cloud deployment model
Cloud deployment model
Auto ScalingGroup
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
Elastic LoadBalancer
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
Amazon MachineImage
Elastic LoadBalancer
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
SecurityGroup
Amazon MachineImage
Elastic LoadBalancer
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
SecurityGroup
Amazon MachineImage
Instances
Elastic LoadBalancer
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
SecurityGroup
Amazon MachineImage
Instances
Elastic LoadBalancer
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
SecurityGroup
Amazon MachineImage
Instances
Elastic LoadBalancer
Cloud deployment model
Auto ScalingGroup
LaunchConfiguration
SecurityGroup
Amazon MachineImage
Instances
Elastic LoadBalancer
Cloud deployment model
Cloud deployment model
Search
Cloud deployment model
API Search
Cloud deployment model
API
Ratings
Search
Cloud deployment modelStreaming Starts
API
Ratings
Search
Cloud deployment modelStreaming Starts
Autocomplete API
Ratings
Search
Cloud deployment modelStreaming Starts
Autocomplete API
Sign Up
Ratings
Search
Cloud deployment modelStreaming Starts
Autocomplete API
Sign Up
Ratings
Search
ApplicationApplication
ApplicationApplication
Application
Application
Inventing the Application
Inventing the ApplicationProblem:
Application is not an Amazon concept
Inventing the ApplicationProblem:
Application is not an Amazon concept
Solution:
Create an Application database in the cloud
Enforce naming conventions on Amazon objects
Fast Rollback
Fast RollbackOptimism causes outages
Fast RollbackOptimism causes outages
Production traffic is unique
Fast RollbackOptimism causes outages
Production traffic is unique
Keep old version running
Fast RollbackOptimism causes outages
Production traffic is unique
Keep old version running
Switch traffic to new version
Fast RollbackOptimism causes outages
Production traffic is unique
Keep old version running
Switch traffic to new version
Monitor results
Fast RollbackOptimism causes outages
Production traffic is unique
Keep old version running
Switch traffic to new version
Monitor results
Revert traffic quickly
Fast Rollback
Fast Rollback
api-usprod-v007
api-frontend
Fast Rollback
api-usprod-v007
api-frontend
api-usprod-v008
Fast Rollback
api-usprod-v007
api-frontend
api-usprod-v008
Fast Rollback
api-usprod-v007
api-frontend
api-usprod-v008
Fast Rollback
api-usprod-v007
api-frontend
api-usprod-v008
Fast Rollback
api-usprod-v007
api-frontend
Inventing the Cluster
Inventing the ClusterProblem:
Two ASGs with one function but different names
Inventing the ClusterProblem:
Two ASGs with one function but different names
Solution:
Append version number in reserved format
Parse ASG name to determine long-term “cluster”
Inventing the Cluster
api
api-usprod
api-usprod-v007
api-usprod-v008
Application
Cluster
Auto Scaling Group
Auto Scaling Group
Instead of keeping a database in sync, use naming conventions to store the source in truth in Amazon’s API
Database Aversion
Database AversionStoring metadata on cloud objects
Database Aversion
Database Aversion
Naming conventions
Database Aversion
Naming conventions
Tagging conventions
Database Aversion
Naming conventions
Tagging conventions
No GORM domain objects
Database Aversion
Naming conventions
Tagging conventions
No GORM domain objects
AWS Java SDK
Database Aversion
Naming conventions
Tagging conventions
No GORM domain objects
AWS Java SDK
Less to go out of sync
Database Aversion
Naming conventions
Tagging conventions
No GORM domain objects
AWS Java SDK
Less to go out of sync
Shared source of truth
Caching the Cloud
Caching the CloudResponsive, massive, multi-region metadata
Caching the Cloud
Caching the Cloud
Large counts
Caching the Cloud
Large counts
Many types
Caching the Cloud
Large counts
Many types
Complex relationships
Caching the Cloud
Large counts
Many types
Complex relationships
Multiple regions
Caching the Cloud
Large counts
Many types
Complex relationships
Multiple regions
Consistent single objects
Caching the Cloud
Large counts
Many types
Complex relationships
Multiple regions
Consistent single objects
Eventually consistent lists
class Caches { final CachedMap<AppRegistration> allApplications final CachedMap<ApplicationMetrics> allApplicationMetrics final CachedMap<HardwareProfile> allHardwareProfiles final MultiRegionCachedMap<MetricAlarm> allAlarms final MultiRegionCachedMap<ApplicationInstance> allApplicationInstances final MultiRegionCachedMap<AutoScalingGroup> allAutoScalingGroups final MultiRegionCachedMap<AvailabilityZone> allAvailabilityZones final MultiRegionCachedMap<Cluster> allClusters final MultiRegionCachedMap<DBInstance> allDBInstances final MultiRegionCachedMap<DBSecurityGroup> allDBSecurityGroups final MultiRegionCachedMap<DBSnapshot> allDBSnapshots final MultiRegionCachedMap<String> allDomains final MultiRegionCachedMap<FastProperty> allFastProperties final MultiRegionCachedMap<Image> allImages final MultiRegionCachedMap<Instance> allInstances final MultiRegionCachedMap<InstanceTypeData> allInstanceTypes final MultiRegionCachedMap<KeyPairInfo> allKeyPairs final MultiRegionCachedMap<LaunchConfiguration> allLaunchConfigurations // etc. // etc. // etc.}
Caching the Cloud
class Caches { final CachedMap<AppRegistration> allApplications final CachedMap<ApplicationMetrics> allApplicationMetrics final CachedMap<HardwareProfile> allHardwareProfiles final MultiRegionCachedMap<MetricAlarm> allAlarms final MultiRegionCachedMap<ApplicationInstance> allApplicationInstances final MultiRegionCachedMap<AutoScalingGroup> allAutoScalingGroups final MultiRegionCachedMap<AvailabilityZone> allAvailabilityZones final MultiRegionCachedMap<Cluster> allClusters final MultiRegionCachedMap<DBInstance> allDBInstances final MultiRegionCachedMap<DBSecurityGroup> allDBSecurityGroups final MultiRegionCachedMap<DBSnapshot> allDBSnapshots final MultiRegionCachedMap<String> allDomains final MultiRegionCachedMap<FastProperty> allFastProperties final MultiRegionCachedMap<Image> allImages final MultiRegionCachedMap<Instance> allInstances final MultiRegionCachedMap<InstanceTypeData> allInstanceTypes final MultiRegionCachedMap<KeyPairInfo> allKeyPairs final MultiRegionCachedMap<LaunchConfiguration> allLaunchConfigurations // etc. // etc. // etc.}
Caching the Cloudclass Caches { final CachedMap<AppRegistration> allApplications final CachedMap<ApplicationMetrics> allApplicationMetrics final CachedMap<HardwareProfile> allHardwareProfiles final MultiRegionCachedMap<MetricAlarm> allAlarms final MultiRegionCachedMap<ApplicationInstance> allApplicationInstances final MultiRegionCachedMap<AutoScalingGroup> allAutoScalingGroups final MultiRegionCachedMap<AvailabilityZone> allAvailabilityZones final MultiRegionCachedMap<Cluster> allClusters final MultiRegionCachedMap<DBInstance> allDBInstances final MultiRegionCachedMap<DBSecurityGroup> allDBSecurityGroups final MultiRegionCachedMap<DBSnapshot> allDBSnapshots final MultiRegionCachedMap<String> allDomains final MultiRegionCachedMap<FastProperty> allFastProperties final MultiRegionCachedMap<Image> allImages final MultiRegionCachedMap<Instance> allInstances final MultiRegionCachedMap<InstanceTypeData> allInstanceTypes final MultiRegionCachedMap<KeyPairInfo> allKeyPairs final MultiRegionCachedMap<LaunchConfiguration> allLaunchConfigurations // etc. // etc. // etc.}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
Caching the Cloudclass AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
Caching the Cloudclass AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
Caching the Cloudclass AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
Caching the Cloudclass AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
class AwsRdsService implements CacheInitializer, InitializingBean {
MultiRegionAwsClient<AmazonRDS> awsClient Caches caches
void initializeCaches() { caches.allDBInstances.ensureSetUp({ Region region -‐> retrieveDBInstances(region) }) }
private List<DBInstance> retrieveDBInstances(Region region) { awsClient.by(region).describeDBInstances(new DescribeDBInstancesRequest()).getDBInstances() }
Collection<DBInstance> getDBInstances(UserContext userContext) { caches.allDBInstances.by(userContext.region).list() }}
Caching the Cloud
Visual Language for the Cloud
Visual Language for the CloudTango open source icons
Visual Language for the Cloud
Visual Language for the Cloud
AWS is intimidating
Visual Language for the Cloud
AWS is intimidating
Many object types
Visual Language for the Cloud
AWS is intimidating
Many object types
Help newbie users
Visual Language for the Cloud
AWS is intimidating
Many object types
Help newbie users
Reduce cognitive load
Visual Language for the Cloud
AWS is intimidating
Many object types
Help newbie users
Reduce cognitive load
Make it easy
Visual Language for the Cloud
AWS is intimidating
Many object types
Help newbie users
Reduce cognitive load
Make it easy
Avoid surprises
Visual Language for the Cloud
Visual Language for the Cloud
At a glance, these nav bar items look alike.
Visual Language for the Cloud
At a glance, these nav bar items look alike.
Visual Language for the Cloud
Visual Language for the Cloud
Some screens have multiple action buttons that look too similar.
Visual Language for the Cloud
Some screens have multiple action buttons that look too similar.
Visual Language for the Cloud
Visual Language for the Cloud
Because of naming conventions, these links look alike.
Visual Language for the Cloud
Because of naming conventions, these links look alike.
Visual Language for the Cloud
Visual Language for the CloudThe indicators for the current AWS region are too easy to miss.
Visual Language for the CloudThe indicators for the current AWS region are too easy to miss.
Visual Language for the Cloud
These availability zones are important to recognize at a glance but their names look similar, and they appear on many screens.
Visual Language for the Cloud
These availability zones are important to recognize at a glance but their names look similar, and they appear on many screens.
Visual Language for the Cloud
Tango Icons
Tango Iconshttp://tango.freedesktop.org/
Tango Iconshttp://tango.freedesktop.org/http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines
Tango Iconshttp://tango.freedesktop.org/http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines
http://commons.wikimedia.org/wiki/Tango_icons
Tango Iconshttp://tango.freedesktop.org/http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines
http://commons.wikimedia.org/wiki/Tango_icons
Used by Firefox, Jenkins, GIMP, OpenOffice, VMWare
REST API in Grails
REST API in GrailsEnable external mashups with cloud data
REST API in Grails
REST API in Grails
REST API in Grails
REST API in Grails
REST API in Grails
REST API in Grails
REST API in Grails
REST API in Grails
REST API in Grails
REST API in Grailsdef show = { String name = params.id UserContext userContext = UserContext.of(request) AppRegistration app = applicationService.getRegisteredApplication(userContext, name) def groups = awsAutoScalingService.getAutoScalingGroupsForApp(userContext, name) List<String> clusterNames = groups.collect { Relationships.clusterFromGroupName(it.autoScalingGroupName) }.unique() Map details = [ app: app, strictName: Relationships.checkStrictName(app.name), clusters: clusterNames, groups: groups, balancers: awsLoadBalancerService.getLoadBalancersForApp(userContext, name), securities: awsEc2Service.getSecurityGroupsForApp(userContext, name), appSecurityGroup: awsEc2Service.getSecurityGroup(userContext, name), launches: awsAutoScalingService.getLaunchConfigurationsForApp(userContext, name), ] withFormat { html { return details } xml { new XML(details).render(response) } json { new JSON(details).render(response) } }}
ApplicationController.groovy
Offline Development
Offline DevelopmentMakes on a plane
Offline DevelopmentMock data
Mock behavior
System property switch offline=true
Mock Datahttp://asgardprod/us-east-1/autoScaling/list.json
Mock DataParse JSON
Mock BehaviorOverride Amazon Java client methods
System Propertygrails run-app -Doffline=true
Why not the AWS console?
Why not the AWS console?
Why not the AWS console?
Why not the AWS console?Hide keys
Why not the AWS console?Hide keys
Customize model
Why not the AWS console?Hide keys
Customize model
Enforce conventions
Why not the AWS console?Hide keys
Customize model
Enforce conventions
Automate workflow
Why not the AWS console?Hide keys
Customize model
Enforce conventions
Automate workflow
Log changes
Why not the AWS console?Hide keys
Customize model
Enforce conventions
Automate workflow
Log changes
Integrate systems
Why not the AWS console?Hide keys
Customize model
Enforce conventions
Automate workflow
Log changes
Integrate systems
Customize REST API
@NetflixOSS
@NetflixOSShttp://techblog.netflix.comhttp://netflix.github.io
Thank you
http://github.com/Netflix/asgard
Thank youQuestions?
@AsgardOSS @joesondow jobs.netflix.com
http://github.com/Netflix/asgard