├── src ├── test │ ├── resources │ │ ├── bar.properties │ │ ├── foo.conf │ │ └── test_plugins │ │ │ └── silly.jar │ ├── ruby │ │ ├── chef │ │ │ └── chef-solo.rb │ │ ├── ex1 │ │ │ ├── sys-external.rb │ │ │ ├── system-template-with-import.rb │ │ │ ├── galaxy-template.rb │ │ │ ├── system-template-with-external.rb │ │ │ ├── static-tagged.rb │ │ │ ├── env-with-listener.rb │ │ │ ├── simple-environment.rb │ │ │ ├── chef-server.rb │ │ │ ├── system-template.rb │ │ │ └── simple-system.rb │ │ ├── test_jruby_template_parser_env_servers-sys.rb │ │ ├── test_jruby_template_parser_templatization-sys.rb │ │ ├── test_jruby_template_parser_test_virtual_installer-sys.rb │ │ ├── test_jruby_template_parser_env_servers-env.rb │ │ ├── test_jruby_template_parser-environment-with-import.rb │ │ ├── test_jruby_template_parser_test_virtual_installer-env.rb │ │ ├── test_updates_env.rb │ │ ├── test_reinflation_env.rb │ │ ├── test_jruby_template_parser-test-overrides.rb │ │ ├── test_reinflation_sys.rb │ │ ├── test_updates_sys_1.rb │ │ ├── test_updates_sys_2.rb │ │ ├── test_jruby_template_parser_templatization-env.rb │ │ ├── test_template.rb │ │ ├── test_initialization.rb │ │ ├── test_atlas_initializer.rb │ │ ├── test_galaxy_installer.rb │ │ ├── test_micro_galaxy_installer.rb │ │ └── base │ │ │ └── system.rb │ └── java │ │ ├── com │ │ └── ning │ │ │ └── atlas │ │ │ ├── tree │ │ │ ├── Pancake.java │ │ │ ├── Waffle.java │ │ │ ├── TestMagicVisitor.java │ │ │ └── TestTrees.java │ │ │ ├── space │ │ │ ├── TestInMemorySpace.java │ │ │ ├── TestSQLiteBackedSpace.java │ │ │ └── TestSpaceQuery.java │ │ │ ├── TestStringTemplateBehavior.java │ │ │ ├── TestSnakeYamlBehavior.java │ │ │ ├── components │ │ │ ├── aws │ │ │ │ ├── TestAWSConfigurator.java │ │ │ │ └── TestEC2SecurityGroupProvisioner.java │ │ │ └── TestSSHKeyPairGenerator.java │ │ │ ├── TestReinflation.java │ │ │ ├── TestGuavaNotificationBus.java │ │ │ ├── TestJavaURI.java │ │ │ ├── testing │ │ │ └── AtlasMatchers.java │ │ │ ├── TestCacheBehavior.java │ │ │ ├── TestIdentity.java │ │ │ ├── ListenerThing.java │ │ │ ├── spi │ │ │ └── TestMaybe.java │ │ │ ├── config │ │ │ └── TestConfiguration.java │ │ │ ├── TestProvisioning.java │ │ │ ├── TestLibraryBehaviors.java │ │ │ └── TestScratchInstaller.java │ │ └── TestCruft.java ├── main │ ├── java │ │ └── com │ │ │ └── ning │ │ │ └── atlas │ │ │ ├── StepType.java │ │ │ ├── logging │ │ │ ├── Level.java │ │ │ └── ColorizedAppender.java │ │ │ ├── tree │ │ │ ├── Tree.java │ │ │ ├── Visitor.java │ │ │ ├── BaseVisitor.java │ │ │ └── Trees.java │ │ │ ├── spi │ │ │ ├── Scratch.java │ │ │ ├── Component.java │ │ │ ├── space │ │ │ │ ├── Core.java │ │ │ │ ├── Missing.java │ │ │ │ ├── Space.java │ │ │ │ └── SpaceKey.java │ │ │ ├── bus │ │ │ │ ├── NotificationBus.java │ │ │ │ ├── ServerEvent.java │ │ │ │ ├── StartServerProvision.java │ │ │ │ ├── FinishedServerProvision.java │ │ │ │ ├── StartServerInstall.java │ │ │ │ ├── FinishedServerInstall.java │ │ │ │ ├── StartServerInstallSequence.java │ │ │ │ ├── FinishedServerInstallSequence.java │ │ │ │ └── Subscribe.java │ │ │ ├── Node.java │ │ │ ├── Deployment.java │ │ │ ├── LifecycleListener.java │ │ │ ├── Provisioner.java │ │ │ ├── Installer.java │ │ │ ├── BaseComponent.java │ │ │ ├── protocols │ │ │ │ ├── Server.java │ │ │ │ ├── Database.java │ │ │ │ └── SSHCredentials.java │ │ │ ├── BaseLifecycleListener.java │ │ │ ├── Status.java │ │ │ └── My.java │ │ │ ├── components │ │ │ ├── aws │ │ │ │ └── AWSConfig.java │ │ │ ├── WaitForScratchValueInstaller.java │ │ │ ├── ErrorInstaller.java │ │ │ ├── ErrorProvisioner.java │ │ │ ├── noop │ │ │ │ ├── NoOpInstaller.java │ │ │ │ └── NoOpProvisioner.java │ │ │ ├── ExecInstaller.java │ │ │ ├── ScratchInstaller.java │ │ │ ├── databases │ │ │ │ └── MysqlLoaderInstaller.java │ │ │ ├── packages │ │ │ │ ├── GemInstaller.java │ │ │ │ ├── AptInstaller.java │ │ │ │ ├── ZipInstaller.java │ │ │ │ └── TarballInstaller.java │ │ │ ├── files │ │ │ │ ├── FileInstaller.java │ │ │ │ ├── ScriptInstaller.java │ │ │ │ └── ERBFileInstaller.java │ │ │ ├── galaxy │ │ │ │ └── MicroGalaxyInstaller.java │ │ │ └── SSHKeyPairGenerator.java │ │ │ ├── base │ │ │ ├── MapConfigSource.java │ │ │ ├── Threads.java │ │ │ └── MorePredicates.java │ │ │ ├── Bunch.java │ │ │ ├── Description.java │ │ │ ├── main │ │ │ ├── Main.java │ │ │ ├── CommandDescriptions.java │ │ │ ├── Destroy.java │ │ │ ├── Converge.java │ │ │ └── ListCommand.java │ │ │ ├── Instantiator.java │ │ │ ├── UriTemplate.java │ │ │ ├── HostDeploymentDescription.java │ │ │ ├── plugin │ │ │ └── PluginSystem.java │ │ │ ├── Element.java │ │ │ ├── Host.java │ │ │ ├── bus │ │ │ ├── AllowConcurrentEvents.java │ │ │ ├── HandlerFindingStrategy.java │ │ │ ├── SynchronizedEventHandler.java │ │ │ ├── GuavaNotificationBus.java │ │ │ └── DeadEvent.java │ │ │ ├── ActualScratch.java │ │ │ ├── SystemMap.java │ │ │ ├── SystemTemplate.java │ │ │ ├── InstallerCache.java │ │ │ ├── space │ │ │ ├── SpaceQuery.java │ │ │ ├── InMemorySpace.java │ │ │ └── QueryParser.java │ │ │ ├── Base.java │ │ │ ├── Template.java │ │ │ ├── JRubyTemplateParser.java │ │ │ ├── Descriptor.java │ │ │ └── config │ │ │ └── AtlasConfiguration.java │ ├── resources │ │ ├── ubuntu-chef-solo-solo.st │ │ ├── s3_init.rb.st │ │ ├── vbox │ │ │ └── createvm.sh │ │ ├── ubuntu-chef-solo-setup.sh │ │ └── log4j.xml │ └── ruby │ │ └── atlas │ │ └── tools │ │ └── rc.rb └── site │ └── pandoc │ ├── building.md │ ├── running.md │ ├── index.md │ ├── pandoc.css │ └── template.html ├── README ├── .gitignore ├── TODO └── notes ├── upgrading_a_system.org └── phases-of-system-creation.org /src/test/resources/bar.properties: -------------------------------------------------------------------------------- 1 | foo.bang = 9 -------------------------------------------------------------------------------- /src/test/ruby/chef/chef-solo.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/test/resources/foo.conf: -------------------------------------------------------------------------------- 1 | foo { 2 | bar = 7 3 | baz = 8 4 | } -------------------------------------------------------------------------------- /src/test/resources/test_plugins/silly.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ning/atlas/HEAD/src/test/resources/test_plugins/silly.jar -------------------------------------------------------------------------------- /src/test/ruby/ex1/sys-external.rb: -------------------------------------------------------------------------------- 1 | 2 | server "woof", :base => "ubuntu-small" 3 | server "meow", :base => "ubuntu-small" 4 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/tree/Pancake.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.tree; 2 | 3 | public class Pancake extends Waffle 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser_env_servers-sys.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | system "magical" do 4 | 5 | server "eng-thing", :base => "mythical" 6 | end -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | # Projecy is Dead / Unmaintained 2 | 3 | Use for heuristic value only :-) 4 | 5 | Read the documentation at http://ning.github.io/atlas 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/StepType.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | public enum StepType 4 | { 5 | Provision, Initialize, Install 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/logging/Level.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.logging; 2 | 3 | public enum Level 4 | { 5 | DEBUG, INFO, WARN, ERROR 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser_templatization-sys.rb: -------------------------------------------------------------------------------- 1 | server "database", { 2 | :base => "mysql:blog", 3 | :install => "scratch:wordpress-db=@" 4 | } 5 | -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser_test_virtual_installer-sys.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | system "test" do 4 | server "thing", { 5 | :base => "server", 6 | :install => "jdbi:3.0.2" 7 | } 8 | end -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser_env_servers-env.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | environment "unit-test" do 4 | base "mythical", :provisioner => "noop" 5 | 6 | server "ops-thing", :base => "mythical" 7 | end -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/tree/Tree.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.tree; 2 | 3 | import java.util.Collection; 4 | 5 | public interface Tree 6 | { 7 | Collection getChildren(); 8 | } 9 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/system-template-with-import.rb: -------------------------------------------------------------------------------- 1 | system "with-import" do 2 | import "external", :url => "#{File.dirname __FILE__}/sys-external.rb" 3 | server "resolver", :base => "ubuntu-small" 4 | end 5 | -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser-environment-with-import.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | environment "unit-test" do 4 | import "thingy", :url => "#{File.dirname __FILE__}/test_jruby_template_parser_env_servers-env.rb" 5 | end -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/Scratch.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | public interface Scratch 4 | { 5 | public void put(String key, String value); 6 | 7 | public Maybe get(String key); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/Component.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | public interface Component 4 | { 5 | public void start(Deployment deployment); 6 | public void finish(Deployment deployment); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/test/java/com/ning/atlas/TestAWSLocal.java 2 | atlas.log 3 | .atlasrc 4 | .DS_Store 5 | .rbenv* 6 | \#*\# 7 | .\#* 8 | *.iml 9 | .idea 10 | target 11 | tmp 12 | .awscreds 13 | *.swp 14 | .classpath 15 | .project 16 | .settings 17 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/space/Core.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.space; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | 5 | public class Core 6 | { 7 | public static final Identity ID = Identity.root().createChild("atlas", "core"); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/galaxy-template.rb: -------------------------------------------------------------------------------- 1 | 2 | # an external template defining galaxy! (see system-parser.rb) 3 | 4 | server "geponsole", :base => "ubuntu-small", 5 | :install => ["chef:gepo-2.7", "chef:gonsole-2.7"], 6 | :order => 10 # not yet supported 7 | -------------------------------------------------------------------------------- /src/main/resources/ubuntu-chef-solo-solo.st: -------------------------------------------------------------------------------- 1 | require "#{File.expand_path(File.dirname(__FILE__))}/s3_init.rb" 2 | 3 | file_cache_path "/var/chef-solo" 4 | cookbook_path "/var/chef-solo/cookbooks" 5 | role_path "/var/chef-solo/roles" 6 | recipe_url "$recipe_url$" 7 | json_attribs "/etc/chef/node.json" 8 | -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser_test_virtual_installer-env.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | environment "test" do 4 | 5 | installer "jdbi", 6 | :virtual => ["noop:{virtual.fragment}", 7 | "noop:octopus"] 8 | 9 | base "server", :provisioner => "noop" 10 | 11 | end -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/tree/Visitor.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.tree; 2 | 3 | public interface Visitor 4 | { 5 | BatonType enter(TreeType node, BatonType baton); 6 | 7 | BatonType on(TreeType node, BatonType baton); 8 | 9 | BatonType exit(TreeType node, BatonType baton); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/NotificationBus.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | public interface NotificationBus 4 | { 5 | public void subscribe(Scope scope, Object listener); 6 | 7 | public void unsubscribe(Object listener); 8 | 9 | public static enum Scope { 10 | Stage, Deployment 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/ruby/test_updates_env.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | environment "reinflation" do 4 | provisioner "noop", com.ning.atlas.noop.NoOpProvisioner 5 | 6 | installer "galaxy", com.ning.atlas.noop.NoOpInstaller 7 | initializer "chef", com.ning.atlas.noop.NoOpInstaller 8 | 9 | base "server", provisioner: "noop", init: ["chef:role[wombatypus]"] 10 | end 11 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/system-template-with-external.rb: -------------------------------------------------------------------------------- 1 | 2 | system "with-ext" do 3 | system "stuff", :external => "#{File.dirname __FILE__}/sys-external.rb" 4 | server "resolver", :base => "ubuntu-small" 5 | end 6 | 7 | 8 | # examples of per-deploy overrides 9 | 10 | # override "ning/resolver.count", 2 11 | # override "ning/aclu/appcore.count", 2 12 | -------------------------------------------------------------------------------- /src/test/ruby/test_reinflation_env.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | environment "reinflation" do 4 | provisioner "noop", com.ning.atlas.noop.NoOpProvisioner 5 | 6 | installer "galaxy", com.ning.atlas.noop.NoOpInstaller 7 | initializer "chef", com.ning.atlas.noop.NoOpInstaller 8 | 9 | base "server", :provisioner => "noop", :init => ["chef:role[wombatypus]"] 10 | end 11 | -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser-test-overrides.rb: -------------------------------------------------------------------------------- 1 | 2 | system "magic" do 3 | server "app", :base => "ubuntu", :cardinality => 2 4 | end 5 | 6 | environment "prod" do 7 | base "ubuntu", :provisioner => "noop" 8 | end 9 | 10 | environment "test" do 11 | cardinality "/magic.0/app" => 1 12 | 13 | base "ubuntu", :provisioner => "noop" 14 | end 15 | -------------------------------------------------------------------------------- /src/test/ruby/test_reinflation_sys.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | system "reinflation" do 4 | server "kitchen", :base => "server", :install => ["galaxy:appliances-1.3.2"] 5 | system "breakfast" do 6 | server "pancakes", :base => "server", :cardinality => 3, :install => ["galaxy:pancake-1.2.3"] 7 | server "bacon", :base => "server", :cardinality => 2, :install => ["galaxy:bacon-1.2.3"] 8 | end 9 | end -------------------------------------------------------------------------------- /src/test/ruby/test_updates_sys_1.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | system "reinflation" do 4 | server "kitchen", :base => "server", :install => ["galaxy:appliances-1.3.2"] 5 | system "breakfast" do 6 | server "pancakes", :base => "server", :cardinality => 3, :install => ["galaxy:pancake-1.2.3"] 7 | server "bacon", :base => "server", :cardinality => 2, :install => ["galaxy:bacon-1.2.3"] 8 | end 9 | end -------------------------------------------------------------------------------- /src/test/ruby/test_updates_sys_2.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | system "reinflation" do 4 | server "kitchen", :base => "server", :install => ["galaxy:appliances-1.3.2"] 5 | system "breakfast" do 6 | server "pancakes", :base => "server", :cardinality => 3, :install => ["galaxy:pancake-2.0.0"] 7 | server "bacon", :base => "server", :cardinality => 2, :install => ["galaxy:bacon-1.2.3"] 8 | end 9 | end -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/Node.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | import com.ning.atlas.tree.Tree; 4 | 5 | import java.util.Collection; 6 | 7 | public interface Node extends Tree 8 | { 9 | public String getType(); 10 | public String getName(); 11 | public My getMy(); 12 | 13 | public Collection getChildren(); 14 | 15 | Identity getId(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/ruby/atlas/tools/rc.rb: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | 3 | module Atlas 4 | 5 | module Tools 6 | module RC 7 | 8 | def self.read_rc 9 | if File.exist? ".atlasrc" 10 | YAML.load_file(".atlasrc") 11 | elsif File.exists? "#{ENV['HOME']}/.atlasrc" 12 | YAML.load_file("#{ENV['HOME']}/.atlasrc") 13 | end 14 | end 15 | 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /src/test/ruby/test_jruby_template_parser_templatization-env.rb: -------------------------------------------------------------------------------- 1 | environment "breakfast" do 2 | 3 | base "mysql", { 4 | :provisioner => ["rds", { 5 | :name => '{base.fragment}', 6 | :storage_size => '5', 7 | :instance_class => "db.m1.small", 8 | :engine => "MySQL", 9 | :username => "wp", 10 | :password => "wp" 11 | }] 12 | } 13 | end -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/ServerEvent.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | 5 | public abstract class ServerEvent 6 | { 7 | private final Identity serverId; 8 | 9 | public ServerEvent(Identity serverId) { 10 | 11 | this.serverId = serverId; 12 | } 13 | 14 | public Identity getServerId() 15 | { 16 | return serverId; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/site/pandoc/building.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | The easiest way to build atlas, is to use [rake](http://rake.rubyforge.org/) 4 | which usually comes with any decent ruby installation: 5 | 6 | rake package 7 | 8 | This will invoke Maven and generate an executable ``atlas`` file. 9 | 10 | You can also do this manually: 11 | 12 | mvn install 13 | cat target/atlas-*.jar >> target/atlas 14 | chmod +x target/atlas 15 | 16 | -------------------------------------------------------------------------------- /src/test/ruby/test_template.rb: -------------------------------------------------------------------------------- 1 | require "/Users/brianm/src/atlas/src/main/ruby/atlas/parser.rb" 2 | require "/Users/brianm/src/atlas/target/atlas-0.0.1-SNAPSHOT.jar" 3 | require "/Users/brianm/.m2/repository/com/google/guava/guava/r09/guava-r09.jar" 4 | 5 | puts Atlas.parse_system("/Users/brianm/src/atlas/src/test/ruby/ex1/system-template.rb") 6 | 7 | puts Atlas.parse_env("/Users/brianm/src/atlas/src/test/ruby/ex1/simple-environment.rb") 8 | 9 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/components/aws/AWSConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components.aws; 2 | 3 | import org.skife.config.Config; 4 | 5 | public abstract class AWSConfig 6 | { 7 | @Config("aws.access-key") 8 | public abstract String getAccessKey(); 9 | 10 | @Config("aws.secret-key") 11 | public abstract String getSecretKey(); 12 | 13 | @Config("aws.key-name") 14 | public abstract String getKeyPairId(); 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/space/TestInMemorySpace.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.space; 2 | 3 | import com.ning.atlas.spi.space.Space; 4 | 5 | import java.io.IOException; 6 | 7 | public class TestInMemorySpace extends BaseSpaceTest 8 | { 9 | @Override 10 | protected Space createSpace() 11 | { 12 | return InMemorySpace.newInstance(); 13 | } 14 | 15 | @Override 16 | protected void destroySpace(Space space) throws IOException 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/Deployment.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | import com.ning.atlas.Environment; 4 | import com.ning.atlas.SystemMap; 5 | import com.ning.atlas.spi.bus.NotificationBus; 6 | import com.ning.atlas.spi.space.Space; 7 | 8 | public interface Deployment 9 | { 10 | public SystemMap getSystemMap(); 11 | public Space getSpace(); 12 | public Scratch getScratch(); 13 | public Environment getEnvironment(); 14 | public NotificationBus getEventBus(); 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/tree/Waffle.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.tree; 2 | 3 | import com.google.common.collect.Lists; 4 | 5 | import java.util.Collection; 6 | import java.util.List; 7 | 8 | public class Waffle implements Tree 9 | { 10 | 11 | private List children; 12 | 13 | public Waffle(Waffle... children) 14 | { 15 | this.children = Lists.newArrayList(children); 16 | } 17 | 18 | public Collection getChildren() 19 | { 20 | return children; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/base/MapConfigSource.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.base; 2 | 3 | import org.skife.config.ConfigSource; 4 | 5 | import java.util.Map; 6 | 7 | public class MapConfigSource implements ConfigSource 8 | { 9 | 10 | private final Map map; 11 | 12 | public MapConfigSource(Map map) 13 | { 14 | this.map = map; 15 | } 16 | 17 | @Override 18 | public String getString(String propertyName) 19 | { 20 | return map.get(propertyName); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/tree/BaseVisitor.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.tree; 2 | 3 | public abstract class BaseVisitor implements Visitor 4 | { 5 | public BatonType enter(TreeType node, BatonType baton) 6 | { 7 | return baton; 8 | } 9 | 10 | public BatonType on(TreeType node, BatonType baton) 11 | { 12 | return baton; 13 | } 14 | 15 | public BatonType exit(TreeType node, BatonType baton) 16 | { 17 | return baton; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/Bunch.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.My; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | 7 | import java.util.List; 8 | 9 | public class Bunch extends Element 10 | { 11 | public Bunch(Identity id, My my, List children) 12 | { 13 | super(id, my, children); 14 | } 15 | 16 | @Override 17 | public String toString() 18 | { 19 | return ToStringBuilder.reflectionToString(this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/Description.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | 5 | import java.util.List; 6 | 7 | public class Description 8 | { 9 | private final List descriptors; 10 | 11 | public Description(Iterable values) 12 | { 13 | this.descriptors = ImmutableList.copyOf(values); 14 | } 15 | 16 | public List getDescriptors() 17 | { 18 | return descriptors; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/s3_init.rb.st: -------------------------------------------------------------------------------- 1 | require 'aws/s3' 2 | 3 | AWS::S3::Base.establish_connection!( 4 | :access_key_id => "$aws_access_key$", 5 | :secret_access_key => "$aws_secret_key$" 6 | ) 7 | 8 | 9 | module URI 10 | class S3 < Generic 11 | def initialize(*args) 12 | @bucket, @file = args[2], args[5][1,args[5].length] 13 | super(*args) 14 | end 15 | 16 | def open &block 17 | http_url = AWS::S3::S3Object.url_for @file, @bucket 18 | URI.parse(http_url).open &block 19 | end 20 | end 21 | @@schemes['S3'] = S3 22 | end 23 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * Identity can be assigned. 2 | This is important for stateful nodes (ie, databases) in case they ar 3 | emoved in the topology. 4 | 5 | * Basic upgrade sequence 6 | Match identity to current installed servers, if matched then build 7 | the next stage from information in the installed node. If there is a 8 | difference that needs to be adjusted, build/execute the upgrade plan 9 | to accomodate the difference. Do not accumulate upgrade plans across 10 | stages, but do it stage by stage. Within a stage, follow the normal 11 | sequence (add, upgrade, remove). 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/StartServerProvision.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.Provisioner; 5 | import com.ning.atlas.spi.Uri; 6 | 7 | public class StartServerProvision extends ServerEvent 8 | { 9 | private final Uri uri; 10 | 11 | public StartServerProvision(Identity serverId, Uri uri) 12 | { 13 | super(serverId); 14 | this.uri = uri; 15 | } 16 | 17 | public Uri getUri() 18 | { 19 | return uri; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/FinishedServerProvision.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.Provisioner; 5 | import com.ning.atlas.spi.Uri; 6 | 7 | public class FinishedServerProvision extends ServerEvent 8 | { 9 | private final Uri uri; 10 | 11 | public FinishedServerProvision(Identity serverId, Uri uri) 12 | { 13 | super(serverId); 14 | this.uri = uri; 15 | } 16 | 17 | public Uri getUri() 18 | { 19 | return uri; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/StartServerInstall.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.Installer; 5 | import com.ning.atlas.spi.Uri; 6 | 7 | public class StartServerInstall extends ServerEvent 8 | { 9 | private final Uri install; 10 | 11 | public StartServerInstall(Identity serverId, Uri install) 12 | { 13 | super(serverId); 14 | this.install = install; 15 | } 16 | 17 | public Uri getInstall() 18 | { 19 | return install; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/FinishedServerInstall.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.Installer; 5 | import com.ning.atlas.spi.Uri; 6 | 7 | public class FinishedServerInstall extends ServerEvent 8 | { 9 | private final Uri install; 10 | 11 | public FinishedServerInstall(Identity serverId, Uri install) 12 | { 13 | super(serverId); 14 | this.install = install; 15 | } 16 | 17 | public Uri getInstall() 18 | { 19 | return install; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/TestStringTemplateBehavior.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.ning.atlas.spi.Uri; 4 | import org.junit.Test; 5 | import org.stringtemplate.v4.ST; 6 | 7 | import static org.hamcrest.CoreMatchers.equalTo; 8 | import static org.junit.Assert.assertThat; 9 | 10 | public class TestStringTemplateBehavior 11 | { 12 | @Test 13 | public void testMapAccess() throws Exception 14 | { 15 | ST st = new ST("hello {base.params.q}", '{', '}'); 16 | st.add("base", Uri.valueOf("scheme:fragment?q=v")); 17 | assertThat(st.render(), equalTo("hello v")); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/space/Missing.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.space; 2 | 3 | public enum Missing 4 | { 5 | 6 | 7 | RequireAll 8 | { 9 | @Override 10 | public Object missing(Class t) 11 | { 12 | throw new IllegalArgumentException("all properties must be present"); 13 | } 14 | }, 15 | NullProperty 16 | { 17 | @Override 18 | public Object missing(Class t) 19 | { 20 | return null; 21 | } 22 | }; 23 | 24 | public abstract Object missing(Class t); 25 | } 26 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/static-tagged.rb: -------------------------------------------------------------------------------- 1 | 2 | environment "test" do 3 | initializer "noop", com.ning.atlas.noop.NoOpInstaller 4 | provisioner "static", com.ning.atlas.StaticTaggedServerProvisioner, :servers => { 5 | "java" => ["10.0.0.1", "10.0.0.2"], 6 | "php" => ["10.0.1.1", "10.0.1.2"] 7 | } 8 | 9 | base "concrete", :tag => "java", :provisioner => "static" 10 | base "macadam", :tag => "php", :provisioner => "static" 11 | end 12 | 13 | 14 | 15 | system "skife" do 16 | server "blog", :base => "concrete" 17 | system "data" do 18 | server "memcached", :base => "macadam", :cardinality => 2 19 | server "db", :base => "concrete" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/space/TestSQLiteBackedSpace.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.space; 2 | 3 | import com.ning.atlas.spi.space.Space; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | 8 | public class TestSQLiteBackedSpace extends BaseSpaceTest 9 | { 10 | private File tmp; 11 | 12 | @Override 13 | protected Space createSpace() throws IOException 14 | { 15 | this.tmp = File.createTempFile("atlas", ".db"); 16 | return SQLiteBackedSpace.create(tmp); 17 | } 18 | 19 | @Override 20 | protected void destroySpace(Space space) throws IOException 21 | { 22 | tmp.delete(); 23 | // NOOP 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/TestCruft.java: -------------------------------------------------------------------------------- 1 | import com.google.common.io.CharStreams; 2 | import org.junit.Ignore; 3 | import org.junit.Test; 4 | 5 | import java.io.InputStreamReader; 6 | import java.net.URI; 7 | 8 | import static org.hamcrest.CoreMatchers.equalTo; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestCruft 12 | { 13 | @Test 14 | @Ignore 15 | public void testFoo() throws Exception 16 | { 17 | URI uri = URI.create("file:///Users/brianm/src/atlas/test.txt?user=atlas&pass=atlas"); 18 | String content = CharStreams.toString(new InputStreamReader(uri.toURL().openStream())); 19 | assertThat(content, equalTo("hello world")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/LifecycleListener.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | import java.util.concurrent.Future; 4 | 5 | public interface LifecycleListener 6 | { 7 | public Future startDeployment(Deployment d); 8 | public Future startProvision(Deployment d); 9 | public Future finishProvision(Deployment d); 10 | public Future startInit(Deployment d); 11 | public Future finishInit(Deployment d); 12 | public Future startInstall(Deployment d); 13 | public Future finishInstall(Deployment d); 14 | public Future startUnwind(Deployment d); 15 | public Future finishUnwind(Deployment d); 16 | public Future finishDeployment(Deployment d); 17 | } 18 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/env-with-listener.rb: -------------------------------------------------------------------------------- 1 | environment "test" do 2 | 3 | set "xn.base-domain" => "waffles.test" 4 | 5 | listener "testy" 6 | 7 | installer "ugx", { 8 | :ssh_user => "ubuntu", 9 | :ssh_key_file => "~/.ec2/brianm-ning.pem", 10 | :ugx_user => "ugx", 11 | :ugx_path => "/home/ugx/deploy" 12 | } 13 | 14 | installer "ubuntu-chef-solo", { 15 | :ssh_user => "ubuntu", 16 | :ssh_key_file => "#{ENV['HOME']}/.ec2/brianm-ning.pem", 17 | :recipe_url => "https://s3.amazonaws.com/chefplay123/chef-solo.tar.gz" 18 | } 19 | 20 | base "ubuntu-small", :provisioner => "noop" 21 | 22 | base "concrete", { 23 | :provisioner => "noop" 24 | } 25 | end 26 | -------------------------------------------------------------------------------- /src/test/ruby/test_initialization.rb: -------------------------------------------------------------------------------- 1 | system "test" do 2 | server "syrup", :base => "concrete", :waffles => "pancakes", :install => ["fancy"] 3 | server "yummy", { base: "concrete", waffles: "pancakes", butter: "yes", install: ["fancy"] } 4 | end 5 | 6 | environment "waffles" do 7 | 8 | initializer "noop", com.ning.atlas.noop.NoOpInstaller 9 | provisioner "static", com.ning.atlas.StaticTaggedServerProvisioner, :servers => { 10 | "java" => ["10.0.0.1", "10.0.0.2"], 11 | "php" => ["10.0.1.1", "10.0.1.2"] 12 | } 13 | installer "fancy", com.ning.atlas.FancyInstaller 14 | 15 | base "concrete", :tag => "java", :provisioner => "static" 16 | base "macadam", :tag => "php", :provisioner => "static" 17 | 18 | end -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/base/Threads.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.base; 2 | 3 | import java.util.Stack; 4 | 5 | public class Threads 6 | { 7 | 8 | private static ThreadLocal> names = new ThreadLocal>() { 9 | @Override 10 | protected Stack initialValue() 11 | { 12 | return new Stack(); 13 | } 14 | }; 15 | 16 | public static void pushName(String t) { 17 | String old_name = Thread.currentThread().getName(); 18 | names.get().push(old_name); 19 | Thread.currentThread().setName(t); 20 | } 21 | 22 | public static void popName() { 23 | Thread.currentThread().setName(names.get().pop()); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/StartServerInstallSequence.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.ning.atlas.spi.Identity; 5 | import com.ning.atlas.spi.Installer; 6 | import com.ning.atlas.spi.Uri; 7 | 8 | import java.util.List; 9 | 10 | public class StartServerInstallSequence extends ServerEvent 11 | { 12 | private final List> installs; 13 | 14 | public StartServerInstallSequence(Identity serverId, List> installs) 15 | { 16 | super(serverId); 17 | this.installs = ImmutableList.copyOf(installs); 18 | } 19 | 20 | public List> getInstalls() 21 | { 22 | return installs; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/FinishedServerInstallSequence.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.bus; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.ning.atlas.spi.Identity; 5 | import com.ning.atlas.spi.Installer; 6 | import com.ning.atlas.spi.Uri; 7 | 8 | import java.util.List; 9 | 10 | public class FinishedServerInstallSequence extends ServerEvent 11 | { 12 | private final List> installs; 13 | 14 | public FinishedServerInstallSequence(Identity serverId, List> installs) 15 | { 16 | super(serverId); 17 | this.installs = ImmutableList.copyOf(installs); 18 | } 19 | 20 | public List> getInstalls() 21 | { 22 | return installs; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/TestSnakeYamlBehavior.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.collect.Maps; 4 | import org.junit.Test; 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.util.Map; 8 | 9 | import static org.hamcrest.CoreMatchers.equalTo; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestSnakeYamlBehavior 13 | { 14 | @SuppressWarnings("unchecked") 15 | @Test 16 | public void testFoo() throws Exception 17 | { 18 | Map it = (Map) new Yaml().load("top:\n child1: hello\n child2: 7"); 19 | Map rs = Maps.newHashMap(); 20 | rs.put("child1", "hello"); 21 | rs.put("child2", 7); 22 | assertThat(it.get("top"), equalTo((Object) rs)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/Provisioner.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | import com.ning.atlas.Host; 4 | 5 | import java.util.concurrent.Future; 6 | 7 | /** 8 | * TODO merge with Installer on Component 9 | */ 10 | public interface Provisioner extends Component 11 | { 12 | public Future provision(Host node, 13 | Uri uri, 14 | Deployment deployment); 15 | 16 | public Future destroy(Identity hostId, 17 | Uri uri, 18 | Deployment deployment); 19 | 20 | public Future describe(Host server, 21 | Uri uri, 22 | Deployment deployment); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/Installer.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | import com.ning.atlas.Host; 4 | 5 | import java.util.concurrent.Future; 6 | 7 | /** 8 | * TODO merge with Installer on Component 9 | */ 10 | public interface Installer extends Component 11 | { 12 | public Future install(final Host server, 13 | final Uri uri, 14 | final Deployment deployment); 15 | 16 | public Future uninstall(final Identity hostId, 17 | final Uri uri, 18 | final Deployment deployment); 19 | 20 | public Future describe(Host server, 21 | Uri uri, 22 | Deployment deployment); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/main/Main.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.main; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | import org.skife.cli.Cli; 6 | import org.skife.cli.Help; 7 | 8 | import com.ning.atlas.config.AtlasConfiguration; 9 | 10 | public class Main 11 | { 12 | @SuppressWarnings("unchecked") 13 | public static void main(String... args) throws Exception 14 | { 15 | Cli.buildCli("atlas", Callable.class) 16 | .withConfiguration(AtlasConfiguration.global()) 17 | .withCommands(Converge.class, 18 | Destroy.class, 19 | ListCommand.class, 20 | SSHCommand.class, 21 | Help.class) 22 | .withDefaultCommand(Help.class) 23 | .build() 24 | .parse(args) 25 | .call(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/Instantiator.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.ning.atlas.logging.Logger; 4 | 5 | import java.lang.reflect.Constructor; 6 | import java.util.Map; 7 | 8 | public class Instantiator 9 | { 10 | private static final Logger log = Logger.get(Instantiator.class); 11 | public static T create(Class type, Map args) throws IllegalAccessException, InstantiationException 12 | { 13 | try { 14 | Constructor c = type.getConstructor(Map.class); 15 | return type.cast(c.newInstance(args)); 16 | } 17 | catch (NoSuchMethodException e) { 18 | // NOOP 19 | } 20 | catch (Exception e) { 21 | log.warn(e, "exception trying to use map constructor on " + type.getName()); 22 | } 23 | return type.newInstance(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/simple-environment.rb: -------------------------------------------------------------------------------- 1 | environment "test" do 2 | 3 | set "xn.base-domain" => "waffles.test" 4 | 5 | installer "ugx", { 6 | :ssh_user => "ubuntu", 7 | :ssh_key_file => "~/.ec2/brianm-ning.pem", 8 | :ugx_user => "ugx", 9 | :ugx_path => "/home/ugx/deploy" 10 | } 11 | 12 | provisioner "ec2", { 13 | :access_key => "", 14 | :secret_key => "", 15 | :keypair_id => "brianm-ning", 16 | } 17 | 18 | installer "ubuntu-chef-solo", { 19 | :ssh_user => "ubuntu", 20 | :ssh_key_file => "#{ENV['HOME']}/.ec2/brianm-ning.pem", 21 | :recipe_url => "https://s3.amazonaws.com/chefplay123/chef-solo.tar.gz" 22 | } 23 | 24 | base "concrete", { 25 | :provisioner => ["ec2", { :tag => "ami-1234"}], 26 | :init => ['ubuntu-chef-solo:{ "run_list": "role[java-core]" }'] 27 | } 28 | end 29 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/BaseComponent.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi; 2 | 3 | import java.util.concurrent.atomic.AtomicReference; 4 | 5 | public abstract class BaseComponent implements Component 6 | { 7 | private final AtomicReference deployment = new AtomicReference(); 8 | 9 | protected Deployment getDeployment() { 10 | return deployment.get(); 11 | } 12 | 13 | @Override 14 | public final void start(Deployment deployment) 15 | { 16 | this.deployment.set(deployment); 17 | startLocal(deployment); 18 | } 19 | 20 | protected void startLocal(Deployment deployment) {} 21 | 22 | @Override 23 | public final void finish(Deployment deployment) 24 | { 25 | this.deployment.set(null); 26 | finishLocal(deployment); 27 | } 28 | 29 | protected void finishLocal(Deployment deployment) {} 30 | } 31 | -------------------------------------------------------------------------------- /src/main/resources/vbox/createvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ---------- 4 | # This script will create the recommended bare hardware 5 | # IMPORTANT: You should manually create the disk and mount the installer iso after running this script 6 | # IMPORTANT: Configure the following before running this script 7 | # ---------- 8 | 9 | VMNAME="atlas-natty32" 10 | BRIDGE_ONLY_ADAPTER="en1: AirPort" # To findout, run $ VBoxManage list bridgedifs 11 | INTNET_ADAPTER="atlas-intnet" 12 | 13 | # ---------- 14 | 15 | VBoxManage createvm --name ${VMNAME} --ostype Ubuntu --register 16 | 17 | VBoxManage modifyvm ${VMNAME} --memory 384 --vram 24 --pae on --usb off --vrde off --audio none 18 | VBoxManage modifyvm ${VMNAME} --nic1 bridged --nictype1 82540EM --bridgeadapter1 "${BRIDGE_ONLY_ADAPTER}" --nicpromisc1 "allow-all" 19 | VBoxManage modifyvm ${VMNAME} --nic2 intnet --nictype2 82540EM --intnet2 ${INTNET_ADAPTER} --nicpromisc2 "allow-vms" 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/UriTemplate.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.ning.atlas.spi.Uri; 4 | import org.stringtemplate.v4.ST; 5 | import org.stringtemplate.v4.compiler.STException; 6 | 7 | import java.util.Map; 8 | 9 | public class UriTemplate 10 | { 11 | private final Uri uri; 12 | 13 | public UriTemplate(Uri uri) 14 | { 15 | this.uri = uri; 16 | } 17 | 18 | public Uri apply(Map args) 19 | { 20 | try { 21 | ST st = new ST(uri.toStringUnEscaped(), '{', '}'); 22 | for (Map.Entry entry : args.entrySet()) { 23 | st.add(entry.getKey(), entry.getValue()); 24 | } 25 | return Uri.valueOf(st.render()); 26 | } 27 | catch (STException e) { 28 | throw new IllegalStateException("Bad stringtemplate evaluation of " + uri + " with " + args, e); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/HostDeploymentDescription.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import com.ning.atlas.spi.Identity; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | public class HostDeploymentDescription 11 | { 12 | private final Map> steps = Maps.newEnumMap(StepType.class); 13 | private final Identity id; 14 | 15 | public HostDeploymentDescription(Identity id) { 16 | this.id = id; 17 | for (StepType stepType : StepType.values()) { 18 | steps.put(stepType, Lists.newArrayList()); 19 | } 20 | } 21 | 22 | public Map> getSteps() 23 | { 24 | return steps; 25 | } 26 | 27 | public Identity getId() 28 | { 29 | return id; 30 | } 31 | 32 | void addStep(StepType type, String description) 33 | { 34 | steps.get(type).add(description); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/space/Space.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.space; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.Maybe; 5 | 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | /** 10 | * @todo Add garbage collection via mark and sweep (marked if read or written during a deployment, sweep at end) 11 | */ 12 | public interface Space 13 | { 14 | void store(Identity id, Object it); 15 | void store(Identity id, String key, String value); 16 | 17 | Maybe get(Identity id, String key); 18 | Maybe get(String idExternalForm, String key); 19 | 20 | Maybe get(Identity id, Class type, Missing behavior); 21 | 22 | Map getAllFor(Identity id); 23 | 24 | Set findAllIdentities(); 25 | 26 | void deleteAll(Identity identity); 27 | 28 | Maybe get(Identity id, Class type); 29 | 30 | void delete(Identity identity, String key); 31 | 32 | Set query(String expression); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/bus/Subscribe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Guava Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ning.atlas.spi.bus; 18 | 19 | 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | @Retention(RetentionPolicy.RUNTIME) 26 | @Target(ElementType.METHOD) 27 | public @interface Subscribe { 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/components/aws/TestAWSConfigurator.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components.aws; 2 | 3 | import com.google.common.base.Splitter; 4 | import com.google.common.collect.ImmutableMap; 5 | import com.google.common.collect.Lists; 6 | import org.junit.Test; 7 | 8 | import java.util.List; 9 | 10 | import static java.util.Arrays.asList; 11 | import static org.hamcrest.CoreMatchers.equalTo; 12 | import static org.junit.Assert.assertThat; 13 | import static org.junit.Assert.fail; 14 | 15 | public class TestAWSConfigurator 16 | { 17 | @Test 18 | public void testFoo() throws Exception 19 | { 20 | try { 21 | new AWSConfigurator(ImmutableMap.of("ssh_foo", "hello@world")); 22 | } catch (Exception e) { 23 | fail(e.getMessage()); 24 | } 25 | } 26 | 27 | @Test 28 | public void testSplitter() throws Exception 29 | { 30 | List i = Lists.newArrayList(Splitter.onPattern("\\s+").split("hello world")); 31 | assertThat(i, equalTo(asList("hello", "world"))); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/plugin/PluginSystem.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.plugin; 2 | 3 | import com.ning.atlas.spi.Installer; 4 | import com.ning.atlas.spi.LifecycleListener; 5 | import com.ning.atlas.spi.Maybe; 6 | import com.ning.atlas.spi.Provisioner; 7 | 8 | import java.util.Map; 9 | 10 | public interface PluginSystem 11 | { 12 | Maybe findProvisioner(String provisioner); 13 | Maybe findListener(String prefix); 14 | Maybe findInstaller(String scheme); 15 | 16 | void registerProvisioner(String prefix, Class type, Map args); 17 | void registerProvisionerConfig(String prefix, Map args); 18 | 19 | void registerInstaller(String prefix, Class type, Map args); 20 | void registerInstallerConfig(String prefix, Map args); 21 | 22 | void registerListener(String prefix, Class type, Map args); 23 | void registerListenerConfig(String prefix, Map args); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/protocols/Server.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.protocols; 2 | 3 | import org.codehaus.jackson.annotate.JsonProperty; 4 | 5 | public class Server 6 | { 7 | private String externalAddress; 8 | private String internalAddress; 9 | 10 | public Server() { } 11 | 12 | public Server(String externalAddress, String internalAddress) { 13 | this.externalAddress = externalAddress; 14 | this.internalAddress = internalAddress; 15 | } 16 | 17 | public Server(String address) { 18 | this(address, address); 19 | } 20 | 21 | @JsonProperty("external_address") 22 | public String getExternalAddress() 23 | { 24 | return externalAddress; 25 | } 26 | 27 | public void setExternalAddress(String externalAddress) 28 | { 29 | this.externalAddress = externalAddress; 30 | } 31 | 32 | @JsonProperty("internal_address") 33 | public String getInternalAddress() 34 | { 35 | return internalAddress; 36 | } 37 | 38 | public void setInternalAddress(String internalAddress) 39 | { 40 | this.internalAddress = internalAddress; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/ruby/test_atlas_initializer.rb: -------------------------------------------------------------------------------- 1 | creds = File.open(".awscreds") do |f| 2 | rs = {} 3 | while line = f.gets 4 | key, name = line.split "=" 5 | rs[key] = name.strip 6 | end 7 | rs 8 | end 9 | 10 | 11 | environment "ec2" do 12 | provisioner "ec2", com.ning.atlas.aws.EC2Provisioner, { 13 | access_key: creds['aws.access-key'], 14 | secret_key: creds['aws.secret-key'], 15 | keypair_id: creds['aws.key-name'] 16 | } 17 | 18 | initializer "atlas", com.ning.atlas.AtlasInstaller, { 19 | :ssh_user => creds['aws.ssh-user'], 20 | :ssh_key_file => creds['aws.key-file-path'] 21 | } 22 | 23 | initializer "chef", com.ning.atlas.chef.UbuntuChefSoloInstaller, { 24 | :ssh_user => creds['aws.ssh-user'], 25 | :ssh_key_file => creds['aws.key-file-path'], 26 | :recipe_url => "https://s3.amazonaws.com/atlas-resources/chef-solo.tar.gz" 27 | } 28 | 29 | base "server", { 30 | :provisioner => "ec2", 31 | :ami => "ami-e2af508b", 32 | :init => ['atlas', 'chef:role[server]'] 33 | } 34 | end 35 | 36 | system "simple" do 37 | server "shell", :base => "server", 38 | :cardinality => ["eshell"] 39 | 40 | 41 | end 42 | -------------------------------------------------------------------------------- /notes/upgrading_a_system.org: -------------------------------------------------------------------------------- 1 | upgrade: 2 | 3 | BoundTemplate.upgradeFrom(InstalledElement root): UpgradePlan 4 | 5 | UpgradePlan is a recursive thing, like the elements. 6 | 7 | * General gist 8 | ** New Servers 9 | - Provision new instances 10 | - Initialize new instances 11 | - Install new instances 12 | ** Changed Servers 13 | - apply new initializations 14 | - uninstall changed installations 15 | - install changed installations 16 | *** Open Questions 17 | - Should we fully reinitialize and re-install? Can we 18 | re-install even? Should we take a chef-like approach of 19 | additive-only? 20 | - Should initializers receive an update() or just re-apply them? 21 | - initializer.update(from, to) ? 22 | - installer.update(from, to) ? 23 | ** Removed Servers 24 | Exactly reverse order of what was done initially. We may want 25 | concept of uninstallers, but for now will wrap into installers. 26 | - uninstall installations 27 | - unintialize initializers 28 | - destroy hosts 29 | 30 | End result needs to be an InstalledSystem, just like the intial 31 | state. 32 | 33 | Is new system creation merely a special case up upgrading from an empty system? It looks like it is, which would be nice. 34 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/protocols/Database.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.protocols; 2 | 3 | public class Database 4 | { 5 | private int port; 6 | private String name; 7 | private String password; 8 | private String username; 9 | private String host; 10 | 11 | public int getPort() 12 | { 13 | return port; 14 | } 15 | 16 | public void setPort(int port) 17 | { 18 | this.port = port; 19 | } 20 | 21 | public String getName() 22 | { 23 | return name; 24 | } 25 | 26 | public void setName(String name) 27 | { 28 | this.name = name; 29 | } 30 | 31 | public String getPassword() 32 | { 33 | return password; 34 | } 35 | 36 | public void setPassword(String password) 37 | { 38 | this.password = password; 39 | } 40 | 41 | public String getUsername() 42 | { 43 | return username; 44 | } 45 | 46 | public void setUsername(String username) 47 | { 48 | this.username = username; 49 | } 50 | 51 | public String getHost() 52 | { 53 | return host; 54 | } 55 | 56 | public void setHost(String host) 57 | { 58 | this.host = host; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/spi/space/SpaceKey.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.spi.space; 2 | 3 | import com.google.common.base.Objects; 4 | import com.google.common.base.Preconditions; 5 | import com.ning.atlas.spi.Identity; 6 | import org.apache.commons.lang3.builder.EqualsBuilder; 7 | 8 | public final class SpaceKey 9 | { 10 | private final Identity id; 11 | private final String key; 12 | 13 | public static SpaceKey from(Identity id, String key) { 14 | return new SpaceKey(id, key); 15 | } 16 | 17 | private SpaceKey(Identity id, String key) { 18 | Preconditions.checkNotNull(id); 19 | Preconditions.checkNotNull(key); 20 | Preconditions.checkArgument(key.length() > 0); 21 | 22 | this.id = id; 23 | this.key = key; 24 | } 25 | 26 | public final Identity getIdentity() 27 | { 28 | return id; 29 | } 30 | 31 | public final String getKey() 32 | { 33 | return key; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) 38 | { 39 | return EqualsBuilder.reflectionEquals(this, o); 40 | } 41 | 42 | @Override 43 | public int hashCode() 44 | { 45 | return Objects.hashCode(id, key); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/components/TestSSHKeyPairGenerator.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components; 2 | 3 | import com.google.common.io.CharStreams; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.io.File; 8 | import java.io.InputStreamReader; 9 | 10 | public class TestSSHKeyPairGenerator 11 | { 12 | @Test 13 | @Ignore 14 | public void testFoo() throws Exception 15 | { 16 | // ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment] [-f output_keyfile] 17 | Process p = new ProcessBuilder("ssh-keygen", 18 | "-b", "1024", 19 | "-t", "rsa", 20 | "-f", "/tmp/foo").start(); 21 | 22 | int exit = p.waitFor(); 23 | if (exit != 0) { 24 | System.out.println(CharStreams.toString(new InputStreamReader(p.getInputStream()))); 25 | System.out.println(CharStreams.toString(new InputStreamReader(p.getErrorStream()))); 26 | } 27 | } 28 | 29 | @Test 30 | 31 | @Ignore 32 | public void testBar() throws Exception 33 | { 34 | System.out.println(new File("tar").getAbsolutePath()); 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/Element.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.My; 5 | import com.ning.atlas.tree.Tree; 6 | import org.apache.commons.lang3.builder.ToStringBuilder; 7 | 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | public class Element implements Tree 12 | { 13 | private final Identity id; 14 | private final My my; 15 | private final List children; 16 | 17 | public Element(Identity id, My my, List children) 18 | { 19 | this.id = id; 20 | this.my = my; 21 | this.children = children; 22 | } 23 | 24 | @Override 25 | public Collection getChildren() 26 | { 27 | return children; 28 | } 29 | 30 | public Identity getId() 31 | { 32 | return id; 33 | } 34 | 35 | public String getType() 36 | { 37 | return id.getType(); 38 | } 39 | 40 | public String getName() 41 | { 42 | return id.getName(); 43 | } 44 | 45 | public My getMy() 46 | { 47 | return my; 48 | } 49 | 50 | @Override 51 | public String toString() 52 | { 53 | return ToStringBuilder.reflectionToString(this); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/Host.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.ning.atlas.spi.Identity; 4 | import com.ning.atlas.spi.Installer; 5 | import com.ning.atlas.spi.My; 6 | import com.ning.atlas.spi.Provisioner; 7 | import com.ning.atlas.spi.Uri; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class Host extends Element 13 | { 14 | private final Uri provisionerUri; 15 | private final List> inits; 16 | private final List> installs; 17 | 18 | public Host(Identity id, 19 | Uri provisionerUri, 20 | List> inits, 21 | List> installs, 22 | My my) 23 | { 24 | super(id, my, Collections.emptyList()); 25 | this.provisionerUri = provisionerUri; 26 | this.inits = inits; 27 | this.installs = installs; 28 | } 29 | 30 | public List> getInstallationUris() 31 | { 32 | return installs; 33 | } 34 | 35 | public List> getInitializationUris() 36 | { 37 | return inits; 38 | } 39 | 40 | public Uri getProvisionerUri() 41 | { 42 | return provisionerUri; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/components/WaitForScratchValueInstaller.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components; 2 | 3 | import com.google.common.util.concurrent.Futures; 4 | import com.ning.atlas.Host; 5 | import com.ning.atlas.spi.Component; 6 | import com.ning.atlas.spi.Deployment; 7 | import com.ning.atlas.spi.Identity; 8 | import com.ning.atlas.spi.Maybe; 9 | import com.ning.atlas.spi.Uri; 10 | 11 | import java.util.concurrent.Future; 12 | 13 | public class WaitForScratchValueInstaller extends ConcurrentComponent 14 | { 15 | @Override 16 | public String perform(Host host, Uri uri, Deployment d) throws Exception 17 | { 18 | 19 | Maybe result = Maybe.unknown(); 20 | while (!result.isKnown()) { 21 | Thread.sleep(100); 22 | result = d.getScratch().get(uri.getFragment()); 23 | } 24 | 25 | return "okay"; 26 | } 27 | 28 | @Override 29 | public String unwind(Identity hostId, Uri uri, Deployment d) throws Exception 30 | { 31 | return "okay"; 32 | } 33 | 34 | @Override 35 | public Future describe(Host server, Uri uri, Deployment deployment) 36 | { 37 | return Futures.immediateFuture("nothing, really"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/base/MorePredicates.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.base; 2 | 3 | import com.google.common.base.Predicate; 4 | 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | 8 | public class MorePredicates 9 | { 10 | public static Predicate beanPropertyEquals(final String name, final Object value) 11 | { 12 | return new Predicate() 13 | { 14 | public boolean apply(T input) 15 | { 16 | try { 17 | Method m = input.getClass().getMethod("get" 18 | + name.substring(0, 1).toUpperCase() 19 | + name.substring(1, name.length())); 20 | return m.invoke(input).equals(value); 21 | } 22 | catch (NoSuchMethodException e) { 23 | return false; 24 | } 25 | catch (InvocationTargetException e) { 26 | throw new IllegalArgumentException(e); 27 | } 28 | catch (IllegalAccessException e) { 29 | throw new IllegalArgumentException(e); 30 | } 31 | } 32 | }; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/TestReinflation.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | public class TestReinflation 4 | { 5 | // @Test 6 | // public void testFoo() throws Exception 7 | // { 8 | // JRubyTemplateParser p = new JRubyTemplateParser(); 9 | // Environment e = p.parseEnvironment(new File("src/test/ruby/test_reinflation_env.rb")); 10 | // Template t = p.parseSystem(new File("src/test/ruby/test_reinflation_sys.rb")); 11 | // 12 | // BoundTemplate bt = t.normalize(e); 13 | // ProvisionedElement pt = bt.provision(new ErrorCollector(),sameThreadExecutor()).get(); 14 | // InitializedTemplate it = pt.initialize(new ErrorCollector(), sameThreadExecutor()).get(); 15 | // InstalledElement inst = it.install(new ErrorCollector(), sameThreadExecutor()).get(); 16 | // 17 | // ObjectMapper mapper = new ObjectMapper(); 18 | // mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); 19 | // String json = mapper.writeValueAsString(inst); 20 | // 21 | // 22 | // Base.DESERIALIZATION_HACK.set(e); 23 | // 24 | // InstalledElement inst2 = mapper.readValue(json, InstalledElement.class); 25 | // 26 | // 27 | // String json2 = mapper.writeValueAsString(inst2); 28 | // 29 | // assertThat(json2, equalTo(json)); 30 | // } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/chef-server.rb: -------------------------------------------------------------------------------- 1 | #aka "ubuntu-small" => "ami-a6f504cf" 2 | chef_server_boot = <<-EOB 3 | #!/bin/sh 4 | # set up a chef-server 5 | # http://wiki.opscode.com/display/chef/Package+Installation+on+Debian+and+Ubuntu 6 | 7 | echo "deb http://apt.opscode.com/ `lsb_release -cs` main" | sudo tee /etc/apt/sources.list.d/opscode.list 8 | 9 | wget -qO - http://apt.opscode.com/packages@opscode.com.gpg.key | sudo apt-key add - 10 | 11 | sudo apt-get update 12 | 13 | sudo apt-get -y install debconf-utils 14 | echo "chef chef/chef_server_url string http://$(hostname -f):4000" >> /tmp/debconf-answers.conf 15 | echo "chef-server-webui chef-server-webui/admin_password password chef" >> /tmp/debconf-answers.conf 16 | echo "chef-solr chef-solr/amqp_password password chef" >> /tmp/debconf-answers.conf 17 | sudo debconf-set-selections < /tmp/debconf-answers.conf 18 | 19 | sudo apt-get -y install build-essential 20 | sudo apt-get -y install libopenssl-ruby 21 | sudo apt-get -y install ruby-dev 22 | sudo apt-get -y install libnet-ssh-multi-ruby 23 | sudo apt-get -y install libhighline-ruby 24 | 25 | 26 | # debconf preseed bits 27 | sudo apt-get -y install chef chef-server 28 | EOB 29 | 30 | 31 | system "chef" do 32 | server "chef-server", :base => "ubuntu-small", 33 | :bootstrap => chef_server_boot 34 | end -------------------------------------------------------------------------------- /src/main/resources/ubuntu-chef-solo-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # set up a chef-server 3 | # http://wiki.opscode.com/display/chef/Package+Installation+on+Debian+and+Ubuntu 4 | 5 | # configure the opscode apt repo 6 | echo "deb http://apt.opscode.com/ `lsb_release -cs` main" | sudo tee /etc/apt/sources.list.d/opscode.list 7 | wget -qO - http://apt.opscode.com/packages@opscode.com.gpg.key | sudo apt-key add - 8 | sudo apt-get update 9 | 10 | # set up answers to debconf questions 11 | sudo apt-get -y install debconf-utils 12 | echo "chef chef/chef_server_url string none" >> /tmp/debconf-answers.conf 13 | sudo debconf-set-selections < /tmp/debconf-answers.conf 14 | 15 | # things chef likes to have installed but doesn't explicitely depend on 16 | sudo apt-get -y install build-essential 17 | sudo apt-get -y install libopenssl-ruby 18 | sudo apt-get -y install ruby-dev 19 | sudo apt-get -y install libnet-ssh-multi-ruby 20 | sudo apt-get -y install libhighline-ruby 21 | 22 | # get aws-s3 so that we can access private files in s3 for coobnook urls 23 | sudo apt-get -y install rubygems1.8 24 | yes |sudo gem install aws-s3 -v 0.6.2 --no-ri --no-rdoc 25 | 26 | #install chef 27 | sudo apt-get -y install chef 28 | sudo /etc/init.d/chef-client stop 29 | 30 | # will hold all the roles, recipes, etc for chef-solo 31 | sudo mkdir -p /var/chef-solo 32 | -------------------------------------------------------------------------------- /src/site/pandoc/running.md: -------------------------------------------------------------------------------- 1 | # Running 2 | 3 | Atlas' commandline 4 | 5 | Invoking atlas without any arguments will show the basic help 6 | 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | $ atlas 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | 11 | Available options are: 12 | 13 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | -e, --env, --environment Environment specification file 15 | -s, --sys, --system System specification file 16 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 | 18 | Atlas requires both these options on the command line: the path to the 19 | [environment specification](#environment-specification) and the path to the 20 | [system specification](#system-specification). Everything else is configured within those two files. 21 | 22 | Commands are: 23 | 24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 | provision Provisions machines/instances. 26 | initialize Initializes the provisioned machines/instances. 27 | install Installs services onto the initialized machines/instances. 28 | start Alias for install. 29 | help Shows basic commandline help. 30 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | 32 | When running against EC2, you should also make sure that before invoking atlas, the ssh key is 33 | registered, e.g.: 34 | 35 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36 | $ ssh-add my-ec2-keypair.pem 37 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 | 39 | # Output 40 | 41 | TBD 42 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/components/ErrorInstaller.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components; 2 | 3 | import com.google.common.util.concurrent.Futures; 4 | import com.ning.atlas.Host; 5 | import com.ning.atlas.spi.BaseComponent; 6 | import com.ning.atlas.spi.Component; 7 | import com.ning.atlas.spi.Deployment; 8 | import com.ning.atlas.spi.Identity; 9 | import com.ning.atlas.spi.Installer; 10 | import com.ning.atlas.spi.Status; 11 | import com.ning.atlas.spi.Uri; 12 | 13 | import java.util.Map; 14 | import java.util.concurrent.Future; 15 | 16 | public class ErrorInstaller extends BaseComponent implements Installer 17 | { 18 | 19 | public ErrorInstaller(Map attributes) 20 | { 21 | 22 | } 23 | 24 | @Override 25 | public Future describe(Host server, Uri uri, Deployment deployment) 26 | { 27 | return Futures.immediateFuture("raise an error"); 28 | } 29 | 30 | @Override 31 | public Future install(Host server, Uri uri, Deployment deployment) 32 | { 33 | return Futures.immediateFuture(Status.fail(uri.getFragment())); 34 | } 35 | 36 | @Override 37 | public Future uninstall(Identity hostId, Uri uri, Deployment deployment) 38 | { 39 | return Futures.immediateFuture(Status.fail("no unwinding of error installaer")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/components/ErrorProvisioner.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components; 2 | 3 | import com.google.common.util.concurrent.Futures; 4 | import com.ning.atlas.Host; 5 | import com.ning.atlas.spi.BaseComponent; 6 | import com.ning.atlas.spi.Component; 7 | import com.ning.atlas.spi.Deployment; 8 | import com.ning.atlas.spi.Identity; 9 | import com.ning.atlas.spi.Provisioner; 10 | import com.ning.atlas.spi.Status; 11 | import com.ning.atlas.spi.Uri; 12 | 13 | import java.util.Map; 14 | import java.util.concurrent.Future; 15 | 16 | public class ErrorProvisioner extends BaseComponent implements Provisioner 17 | { 18 | public ErrorProvisioner(Map args) 19 | { 20 | 21 | } 22 | 23 | public ErrorProvisioner() 24 | { 25 | 26 | } 27 | 28 | @Override 29 | public Future provision(Host node, Uri uri, Deployment deployment) 30 | { 31 | return Futures.immediateFuture(Status.fail(uri.getFragment())); 32 | } 33 | 34 | @Override 35 | public Future destroy(Identity hostId, Uri uri, Deployment deployment) 36 | { 37 | return Futures.immediateFuture(Status.fail("no unprovisioning on he failure provisioner")); 38 | } 39 | 40 | @Override 41 | public Future describe(Host server, Uri uri, Deployment deployment) 42 | { 43 | return Futures.immediateFuture("raise an error"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/site/pandoc/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Atlas is a tool to automatically spin up complete environments consisting of multiple machines 4 | and software installed on them. These environments are described via configuration files which 5 | are fed to Atlas, and Atlas then automatically procures the necessary resources and installs 6 | the base machines and the software running on them. 7 | 8 | Atlas is currently able to spin up environments on EC2 and VirtualBox. 9 | 10 | Atlas is being built by various folks, mostly from [Ning](http://www.ning.com), and is made available under the [Apache License, 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt). 11 | 12 | # Where to get it 13 | 14 | Atlas is on github: [https://github.com/ning/atlas](https://github.com/ning/atlas). 15 | 16 | # 5 minute quick start 17 | 18 | Build it: 19 | 20 | rake package 21 | 22 | Create the [environment specification](#environment-specification) and 23 | [system specification](#system-specification). 24 | 25 | Provision stuff: 26 | 27 | ./target/atlas -e -s provision 28 | 29 | Initialize stuff: 30 | 31 | ./target/atlas -e -s initialize 32 | 33 | Start stuff: 34 | 35 | ./target/atlas -e -s start 36 | 37 | # Mailing list 38 | 39 | We have a [developer mailing list](http://groups.google.com/group/atlas-dev). 40 | 41 | -------------------------------------------------------------------------------- /src/test/ruby/test_galaxy_installer.rb: -------------------------------------------------------------------------------- 1 | creds = File.open(".awscreds") do |f| 2 | rs = {} 3 | while line = f.gets 4 | key, name = line.split "=" 5 | rs[key] = name.strip 6 | puts "#{key}=#{name}" 7 | end 8 | rs 9 | end 10 | 11 | 12 | environment "ec2" do 13 | provisioner com.ning.atlas.aws.EC2Provisioner, { 14 | :access_key => creds['aws.access-key'], 15 | :secret_key => creds['aws.secret-key'], 16 | :keypair_id => creds['aws.key-name'] 17 | } 18 | 19 | initializer "chef", com.ning.atlas.chef.UbuntuChefSoloInstaller, { 20 | :ssh_user => creds['aws.ssh-user'], 21 | :ssh_key_file => creds['aws.key-file-path'], 22 | :recipe_url => "https://s3.amazonaws.com/atlas-resources/chef-solo.tar.gz" 23 | } 24 | 25 | installer "ugx", com.ning.atlas.galaxy.MicroGalaxyInstaller, { 26 | :ssh_user => creds['aws.ssh-user'], 27 | :ssh_key_file => creds['aws.key-file-path'], 28 | :ugx_user => "ubuntu", 29 | :ugx_path => "/home/ubuntu/deploy" 30 | } 31 | 32 | 33 | base "gonsole", { 34 | :ami => "ami-e2af508b", 35 | :init => ['chef:role[gonsole]'] 36 | } 37 | 38 | base "server", { 39 | :ami => "ami-e2af508b", 40 | :init => ['chef:role[server]'] 41 | } 42 | end 43 | 44 | system "simple" do 45 | server "shell", { 46 | :base => "server", 47 | :cardinality => ["eshell"], 48 | :install => ["ugx:https://s3.amazonaws.com/atlas-resources/echo-server-0.0.1.tar.gz"] 49 | } 50 | 51 | end 52 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/bus/AllowConcurrentEvents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Guava Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ning.atlas.bus; 18 | 19 | import com.google.common.annotations.Beta; 20 | 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.lang.annotation.Target; 25 | 26 | /** 27 | * Marks an event handling method as being thread-safe. This annotation 28 | * indicates that EventBus may invoke the event handler simultaneously from 29 | * multiple threads. 30 | * 31 | *

This does not mark the method as an event handler, and so should be used 32 | * in combination with {@link com.ning.atlas.spi.bus.Subscribe}. 33 | * 34 | * @author Cliff Biffle 35 | * @since 10.0 36 | */ 37 | @Retention(RetentionPolicy.RUNTIME) 38 | @Target(ElementType.METHOD) 39 | @Beta 40 | public @interface AllowConcurrentEvents { 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/TestGuavaNotificationBus.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.eventbus.AsyncEventBus; 4 | import com.google.common.eventbus.Subscribe; 5 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 6 | import org.junit.Test; 7 | 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import static org.hamcrest.CoreMatchers.equalTo; 13 | import static org.junit.Assert.assertThat; 14 | 15 | public class TestGuavaNotificationBus 16 | { 17 | @Test 18 | public void testFoo() throws Exception 19 | { 20 | 21 | AsyncEventBus bus = new AsyncEventBus(Executors.newCachedThreadPool(new ThreadFactoryBuilder() 22 | .setDaemon(true) 23 | .setNameFormat("event-bus-%d") 24 | .build())); 25 | 26 | 27 | final CountDownLatch latch = new CountDownLatch(1); 28 | bus.register(new Object() { 29 | @SuppressWarnings("unused") 30 | @Subscribe 31 | public void on(String msg) { 32 | System.out.println(msg); 33 | latch.countDown(); 34 | } 35 | }); 36 | 37 | bus.post("hello world"); 38 | 39 | assertThat(latch.await(1, TimeUnit.SECONDS), equalTo(true)); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/ActualScratch.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.collect.ArrayListMultimap; 4 | import com.google.common.collect.ImmutableList; 5 | import com.google.common.collect.ListMultimap; 6 | import com.google.common.collect.Multimaps; 7 | import com.ning.atlas.logging.Logger; 8 | import com.ning.atlas.spi.Maybe; 9 | import com.ning.atlas.spi.Scratch; 10 | 11 | import java.util.List; 12 | 13 | public class ActualScratch implements Scratch 14 | { 15 | private static final Logger log = Logger.get(ActualScratch.class); 16 | 17 | private final ListMultimap values = Multimaps.synchronizedListMultimap(ArrayListMultimap.create()); 18 | 19 | public void put(String key, String value) 20 | { 21 | synchronized (values) { 22 | log.info("%s = %s", key, value); 23 | values.put(key, value); 24 | } 25 | } 26 | 27 | public Maybe get(String key) 28 | { 29 | synchronized (values) { 30 | if (values.get(key).isEmpty()) { 31 | return Maybe.unknown(); 32 | } 33 | else { 34 | List all = values.get(key); 35 | String rs = all.get(all.size() - 1); // return the last if asking for one value 36 | return Maybe.definitely(rs); 37 | } 38 | } 39 | } 40 | 41 | public List getAllFor(String key) { 42 | synchronized (values) { 43 | return ImmutableList.copyOf(values.get(key)); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/TestJavaURI.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import org.apache.http.NameValuePair; 4 | import org.apache.http.client.utils.URLEncodedUtils; 5 | import org.junit.Test; 6 | 7 | import java.net.URI; 8 | import java.util.List; 9 | 10 | import static org.hamcrest.CoreMatchers.equalTo; 11 | import static org.hamcrest.CoreMatchers.nullValue; 12 | import static org.junit.Assert.assertThat; 13 | 14 | public class TestJavaURI 15 | { 16 | @Test 17 | public void testBasicScheme() throws Exception 18 | { 19 | URI uri = URI.create("cruft:ami-12345"); 20 | assertThat(uri.getScheme(), equalTo("cruft")); 21 | assertThat(uri.getSchemeSpecificPart(), equalTo("ami-12345")); 22 | } 23 | 24 | @Test 25 | public void testBasicSchemeExtensions() throws Exception 26 | { 27 | URI uri = URI.create("cruft:ami-12345://waffles/hello"); 28 | assertThat(uri.getScheme(), equalTo("cruft")); 29 | assertThat(uri.getSchemeSpecificPart(), equalTo("ami-12345://waffles/hello")); 30 | 31 | assertThat(uri.getHost(), nullValue()); 32 | } 33 | 34 | @Test 35 | public void testParams() throws Exception 36 | { 37 | URI uri = URI.create("cruft://waffles/hello?name=Happy"); 38 | List pairs = URLEncodedUtils.parse(uri, "UTF-8"); 39 | assertThat(pairs.size(), equalTo(1)); 40 | for (NameValuePair pair : pairs) { 41 | assertThat(pair.getName(), equalTo("name")); 42 | assertThat(pair.getValue(), equalTo("Happy")); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/testing/AtlasMatchers.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.testing; 2 | 3 | import org.hamcrest.BaseMatcher; 4 | import org.hamcrest.Description; 5 | import org.hamcrest.Matcher; 6 | 7 | import java.io.File; 8 | 9 | public class AtlasMatchers 10 | { 11 | 12 | public static Matcher> containsInstanceOf(final Class type) { 13 | return new BaseMatcher>() 14 | { 15 | @Override 16 | public boolean matches(Object item) 17 | { 18 | Iterable it = Iterable.class.cast(item); 19 | for (Object o : it) { 20 | if (type.isAssignableFrom(o.getClass())) { 21 | return true; 22 | } 23 | } 24 | return false; 25 | } 26 | 27 | @Override 28 | public void describeTo(Description description) 29 | { 30 | description.appendText("iterable to contain an instance of " + type.getName()); 31 | } 32 | }; 33 | } 34 | 35 | public static Matcher exists() 36 | { 37 | return new BaseMatcher() 38 | { 39 | public boolean matches(Object item) 40 | { 41 | File f = (File) item; 42 | return f.exists(); 43 | } 44 | 45 | public void describeTo(Description description) 46 | { 47 | description.appendText("the expected file does not exist"); 48 | } 49 | }; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/ruby/test_micro_galaxy_installer.rb: -------------------------------------------------------------------------------- 1 | creds = File.open(".awscreds") do |f| 2 | rs = {} 3 | while line = f.gets 4 | key, name = line.split "=" 5 | rs[key] = name.strip 6 | puts "#{key}=#{name}" 7 | end 8 | rs 9 | end 10 | 11 | 12 | environment "ec2" do 13 | provisioner "ec2", com.ning.atlas.aws.EC2Provisioner, { 14 | :access_key => creds['aws.access-key'], 15 | :secret_key => creds['aws.secret-key'], 16 | :keypair_id => creds['aws.key-name'] 17 | } 18 | 19 | initializer "chef", com.ning.atlas.chef.UbuntuChefSoloInstaller, { 20 | :ssh_user => creds['aws.ssh-user'], 21 | :ssh_key_file => creds['aws.key-file-path'], 22 | :recipe_url => "https://s3.amazonaws.com/atlas-resources/chef-solo.tar.gz" 23 | } 24 | 25 | installer "ugx", com.ning.atlas.galaxy.MicroGalaxyInstaller, { 26 | :ssh_user => creds['aws.ssh-user'], 27 | :ssh_key_file => creds['aws.key-file-path'], 28 | :ugx_user => "ubuntu", 29 | :ugx_path => "/home/ubuntu/deploy" 30 | } 31 | 32 | 33 | base "gonsole", { 34 | :provisioner => "ec2", 35 | :ami => "ami-e2af508b", 36 | :init => ['chef:role[gonsole]'] 37 | } 38 | 39 | base "server", { 40 | :provisioner => "ec2", 41 | :ami => "ami-e2af508b", 42 | :init => ['chef:role[server]'] 43 | } 44 | end 45 | 46 | system "simple" do 47 | server "shell", { 48 | :base => "server", 49 | :cardinality => ["eshell"], 50 | :install => ["ugx:https://s3.amazonaws.com/atlas-resources/echo-server-0.0.1.tar.gz"] 51 | } 52 | 53 | end 54 | -------------------------------------------------------------------------------- /src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/test/ruby/ex1/system-template.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | environment "cruft" do 4 | # not sure how to use this concept yet, but I will figure it out :-) 5 | end 6 | 7 | 8 | # nasty interpolation to say 'next to this file' :-( 9 | #system "galaxy", :external => "file:///#{File.expand_path(File.dirname(__FILE__))}/galaxy-template.rb" 10 | 11 | #system "chef", :external => "file:///#{File.expand_path(File.dirname(__FILE__))}/chef-server.rb" 12 | 13 | 14 | system "ning" do 15 | server "resolver", :base => "ubuntu-small", 16 | :install => ["cast:load-balancer-9.3"], 17 | :cardinality => 8 18 | 19 | server "single-param-install", :install => ["foo:bar", { :size => 7 } ] 20 | server "single-param-install2", :install => [["foo:bar", { :size => 7 } ]] 21 | server "single-param-install3", :install => ["hello:world", 22 | ["foo:bar", { :size => 7 } ]] 23 | server "single-param-install4", :install => "hello:world" 24 | 25 | system "aclu", :cardinality => ["aclu0", "aclu1"] do 26 | server "appcore", :base => "ubuntu-small", 27 | :count => 5, 28 | :install => ["cast:app-server-2.4.37"], 29 | "xn.raspberry" => [1,2,3], 30 | "waffle" => 7 31 | 32 | server "content", :base => "ubuntu-small", 33 | :cardinality => 2, 34 | :install => ["cast:content-service-1.0.6"] 35 | end 36 | end 37 | 38 | 39 | # examples of per-deploy overrides 40 | 41 | # override "ning/resolver.count", 2 42 | # override "ning/aclu/appcore.count", 2 43 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/bus/HandlerFindingStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Guava Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ning.atlas.bus; 18 | 19 | import com.google.common.collect.Multimap; 20 | 21 | /** 22 | * A method for finding event handler methods in objects, for use by 23 | * {@link com.ning.atlas.bus.EventBus}. 24 | * 25 | * @author Cliff Biffle 26 | */ 27 | interface HandlerFindingStrategy { 28 | 29 | /** 30 | * Finds all suitable event handler methods in {@code source}, organizes them 31 | * by the type of event they handle, and wraps them in {@link com.google.common.eventbus.EventHandler}s. 32 | * 33 | * @param source object whose handlers are desired. 34 | * @return EventHandler objects for each handler method, organized by event 35 | * type. 36 | * 37 | * @throws IllegalArgumentException if {@code source} is not appropriate for 38 | * this strategy (in ways that this interface does not define). 39 | */ 40 | Multimap, EventHandler> findAllHandlers(Object source); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/ning/atlas/TestCacheBehavior.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.cache.CacheBuilder; 4 | import com.google.common.cache.CacheLoader; 5 | import com.google.common.cache.LoadingCache; 6 | import com.google.common.cache.RemovalListener; 7 | import com.google.common.cache.RemovalNotification; 8 | import org.junit.Test; 9 | 10 | import java.util.Set; 11 | import java.util.concurrent.ConcurrentSkipListSet; 12 | 13 | import static org.hamcrest.CoreMatchers.equalTo; 14 | import static org.junit.Assert.assertThat; 15 | 16 | public class TestCacheBehavior 17 | { 18 | @Test 19 | public void testFoo() throws Exception 20 | { 21 | final Set whacked = new ConcurrentSkipListSet(); 22 | LoadingCache sizes = CacheBuilder 23 | .newBuilder() 24 | .removalListener(new RemovalListener() 25 | { 26 | @Override 27 | public void onRemoval(RemovalNotification event) 28 | { 29 | whacked.add(event.getKey()); 30 | } 31 | }) 32 | .maximumSize(Integer.MAX_VALUE) 33 | .build(new CacheLoader() 34 | { 35 | @Override 36 | public Integer load(String key) throws Exception 37 | { 38 | return key.length(); 39 | } 40 | }); 41 | 42 | assertThat(sizes.get("hello"), equalTo(5)); 43 | 44 | sizes.invalidateAll(); 45 | assertThat(whacked.size(), equalTo(1)); 46 | assertThat(whacked.contains("hello"), equalTo(true)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/components/noop/NoOpInstaller.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components.noop; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.util.concurrent.Futures; 5 | import com.ning.atlas.Host; 6 | import com.ning.atlas.spi.BaseComponent; 7 | import com.ning.atlas.spi.Component; 8 | import com.ning.atlas.spi.Deployment; 9 | import com.ning.atlas.spi.Identity; 10 | import com.ning.atlas.spi.Installer; 11 | import com.ning.atlas.spi.Status; 12 | import com.ning.atlas.spi.Uri; 13 | import org.apache.commons.lang3.tuple.Pair; 14 | 15 | import java.util.Collection; 16 | import java.util.concurrent.Future; 17 | 18 | public class NoOpInstaller extends BaseComponent implements Installer 19 | { 20 | private static Collection>> installed = Lists.newArrayList(); 21 | 22 | @Override 23 | public Future describe(Host server, Uri uri, Deployment deployment) 24 | { 25 | return Futures.immediateFuture("do nothing with " + uri); 26 | } 27 | 28 | @Override 29 | public Future install(Host server, Uri uri, Deployment deployment) 30 | { 31 | installed.add(Pair.of(server.getId(), uri)); 32 | return Futures.immediateFuture(Status.okay(uri.toString())); 33 | } 34 | 35 | @Override 36 | public Future uninstall(Identity hostId, Uri uri, Deployment deployment) 37 | { 38 | return Futures.immediateFuture(Status.okay()); 39 | } 40 | 41 | public static Iterable>> getInstalled() 42 | { 43 | return installed; 44 | } 45 | 46 | public static void reset() { 47 | installed.clear(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/SystemMap.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.Iterables; 5 | import com.google.common.collect.Sets; 6 | import com.ning.atlas.tree.Trees; 7 | import org.apache.commons.lang3.builder.ToStringBuilder; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | import java.util.Set; 12 | 13 | import static java.util.Arrays.asList; 14 | 15 | public class SystemMap 16 | { 17 | private final List roots; 18 | 19 | public SystemMap() { 20 | this(Collections.emptyList()); 21 | } 22 | 23 | public SystemMap(Element... elements) { 24 | this(asList(elements)); 25 | } 26 | 27 | public SystemMap(Iterable roots) 28 | { 29 | this.roots = ImmutableList.copyOf(roots); 30 | } 31 | 32 | public static SystemMap emptyMap() 33 | { 34 | return new SystemMap(); 35 | } 36 | 37 | public List getRoots() 38 | { 39 | return roots; 40 | } 41 | 42 | public Set findLeaves() 43 | { 44 | final Set rs = Sets.newLinkedHashSet(); 45 | for (Element root : roots) { 46 | rs.addAll(Trees.findInstancesOf(root, Host.class)); 47 | } 48 | return rs; 49 | } 50 | 51 | public Element getSingleRoot() 52 | { 53 | return roots.get(0); 54 | } 55 | 56 | public SystemMap combine(SystemMap other) 57 | { 58 | return new SystemMap(Iterables.concat(this.getRoots(), other.getRoots())); 59 | } 60 | 61 | @Override 62 | public String toString() 63 | { 64 | return ToStringBuilder.reflectionToString(this); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/components/ExecInstaller.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components; 2 | 3 | import com.google.common.util.concurrent.Futures; 4 | import com.ning.atlas.Host; 5 | import com.ning.atlas.SSH; 6 | import com.ning.atlas.logging.Logger; 7 | import com.ning.atlas.spi.Component; 8 | import com.ning.atlas.spi.Deployment; 9 | import com.ning.atlas.spi.Identity; 10 | import com.ning.atlas.spi.Uri; 11 | 12 | import java.util.Map; 13 | import java.util.concurrent.Future; 14 | 15 | public class ExecInstaller extends ConcurrentComponent 16 | { 17 | private final static Logger log = Logger.get(ExecInstaller.class); 18 | 19 | private final String creds; 20 | 21 | public ExecInstaller(Map attributes) 22 | { 23 | this.creds = attributes.get("credentials"); 24 | } 25 | 26 | @Override 27 | public String perform(Host host, Uri uri, Deployment d) throws Exception 28 | { 29 | SSH ssh = new SSH(host, d.getSpace(), creds); 30 | try { 31 | String out = ssh.exec(uri.getFragment()); 32 | log.info("output of exec is %s", out); 33 | return out; 34 | } 35 | finally { 36 | ssh.close(); 37 | } 38 | } 39 | 40 | @Override 41 | public String unwind(Identity hostId, Uri uri, Deployment d) throws Exception 42 | { 43 | throw new IllegalStateException("No clearing exec actions"); 44 | } 45 | 46 | @Override 47 | public Future describe(Host server, Uri uri, Deployment deployment) 48 | { 49 | return Futures.immediateFuture(String.format("will execute { %s } remotely", uri.getFragment())); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/main/CommandDescriptions.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.main; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * This is attempt to associate descriptions with individual command names, 7 | * found through reflection in the Command enum. 8 | * 9 | * This is something which should be statically declared. However, I'm not 10 | * finding an obvious benefit to creating a HashMap and filling it in 11 | * statically. Therefore, I've taken the age-old approach of "get it working 12 | * now and learn more about the language later" and using a giant switch/case 13 | * structure instead. 14 | * 15 | * @author sfalvo 16 | */ 17 | public class CommandDescriptions { 18 | public static String descriptionForCommand(String cmdName) { 19 | HashMap hm = new HashMap(); 20 | 21 | hm.put("help", 22 | "Displays help on command-line usage and available commands."); 23 | hm.put("ls", 24 | "PLEASE FILL ME IN"); 25 | hm.put("init", 26 | "Initializes the local Atlas configuration to work with your system and environment."); 27 | hm.put("update", 28 | "Updates an existing environment, using the current system and environment as its guide."); 29 | hm.put("start", 30 | "Starts an environment."); 31 | hm.put("ssh", 32 | "SSH to a specific machine, by symbolic name."); 33 | hm.put("destroy", 34 | "Terminate an existing environment."); 35 | 36 | String desc = hm.get(cmdName); 37 | if(desc == null) 38 | desc = "No description for command "+cmdName+" exists."; 39 | 40 | return desc; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/components/ScratchInstaller.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas.components; 2 | 3 | import com.google.common.base.Splitter; 4 | import com.google.common.util.concurrent.Futures; 5 | import com.ning.atlas.Host; 6 | import com.ning.atlas.spi.BaseComponent; 7 | import com.ning.atlas.spi.Component; 8 | import com.ning.atlas.spi.Deployment; 9 | import com.ning.atlas.spi.Identity; 10 | import com.ning.atlas.spi.Installer; 11 | import com.ning.atlas.spi.Status; 12 | import com.ning.atlas.spi.Uri; 13 | 14 | import java.util.Map; 15 | import java.util.concurrent.Future; 16 | 17 | public class ScratchInstaller extends BaseComponent implements Installer 18 | { 19 | 20 | @Override 21 | public Future install(Host server, Uri uri, Deployment deployment) 22 | { 23 | final String id = server.getId().toExternalForm(); 24 | Map pairs = Splitter.on(";").trimResults().withKeyValueSeparator("=").split(uri.getFragment()); 25 | for (Map.Entry entry : pairs.entrySet()) { 26 | final String key = entry.getKey(); 27 | final String value = entry.getValue(); 28 | deployment.getScratch().put(key.replaceAll("@", id), value.replaceAll("@", id)); 29 | 30 | } 31 | 32 | return Futures.immediateFuture(Status.okay("wrote out value")); 33 | } 34 | 35 | @Override 36 | public Future uninstall(Identity hostId, Uri uri, Deployment deployment) 37 | { 38 | return Futures.immediateFuture(Status.okay()); 39 | } 40 | 41 | @Override 42 | public Future describe(Host server, Uri uri, Deployment deployment) 43 | { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/bus/SynchronizedEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Guava Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ning.atlas.bus; 18 | 19 | import java.lang.reflect.InvocationTargetException; 20 | import java.lang.reflect.Method; 21 | 22 | /** 23 | * Wraps a single-argument 'handler' method on a specific object, and ensures 24 | * that only one thread may enter the method at a time. 25 | * 26 | *

Beyond synchronization, this class behaves identically to 27 | * {@link com.google.common.eventbus.EventHandler}. 28 | * 29 | * @author Cliff Biffle 30 | */ 31 | class SynchronizedEventHandler extends EventHandler 32 | { 33 | /** 34 | * Creates a new SynchronizedEventHandler to wrap {@code method} on 35 | * {@code target}. 36 | * 37 | * @param target object to which the method applies. 38 | * @param method handler method. 39 | */ 40 | public SynchronizedEventHandler(Object target, Method method) { 41 | super(target, method); 42 | } 43 | 44 | @Override public synchronized void handleEvent(Object event) 45 | throws InvocationTargetException { 46 | super.handleEvent(event); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/ruby/base/system.rb: -------------------------------------------------------------------------------- 1 | # global aliases 2 | aka "galaxy" => "chef:galaxy-agent" 3 | 4 | space "cruft" do 5 | # what do do/use when running in cruft 6 | 7 | provisioner com.ning.atlas.cruft.EC2OldProvisioner, { 8 | :credential_file => "~/.awscreds" 9 | } 10 | 11 | bootstrapper com.ning.atlas.bootstrap.SSHBootStrapper, { 12 | :key_file => "http://waffles/hello.pem", 13 | :ssh_user => "ubuntu", 14 | :bastion_host => "mrpiffles@bastion.example.com" 15 | } 16 | 17 | base "java-core", :image => "ami-a6f504cf", 18 | :bootstrap => "" 19 | 20 | 21 | base "ubuntu-small" do 22 | image "ami-a6f504cf" 23 | 24 | bootstrap <<-EOS 25 | sudo apt-get -y install chef 26 | chef-solo wibble wibble wibble 27 | EOS 28 | end 29 | 30 | end 31 | 32 | space "xnb3" do 33 | # what do do/use when running in xnb3 34 | 35 | end 36 | 37 | # the actual systems 38 | system "galaxy", :external => "http://galaxy/galaxy-template.rb" 39 | system "chef", :external => "http://chefism/chef-server.rb" 40 | 41 | system "ning" do 42 | server "resolver", :base => "java-core", 43 | :install => ["galaxy:load-balancer-9.3"] 44 | :count => 8 45 | 46 | system "aclu", :count=> 2 do 47 | server "appcore", :base => "java-core", 48 | :count => 5, 49 | :install => ["galaxy:app-server-2.4.37"] 50 | 51 | server "content", :base => "ubuntu-small", 52 | :count => 2, 53 | :install => ["galaxy", "galaxy:content-service-1.0.6"] 54 | end 55 | end 56 | 57 | 58 | # examples of per-deploy overrides 59 | 60 | # override "ning/resolver.count", 2 61 | # override "ning/aclu/appcore.count", 2 62 | -------------------------------------------------------------------------------- /src/main/java/com/ning/atlas/SystemTemplate.java: -------------------------------------------------------------------------------- 1 | package com.ning.atlas; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.Iterables; 5 | import com.google.common.collect.Lists; 6 | import com.ning.atlas.spi.Identity; 7 | import com.ning.atlas.spi.My; 8 | 9 | import java.util.Collection; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | public class SystemTemplate extends Template 14 | { 15 | private final List