Module: ClusterChef

Defined in:
lib/cluster_chef/chef_layer.rb,
lib/cluster_chef.rb,
lib/cluster_chef/cloud.rb,
lib/cluster_chef/facet.rb,
lib/cluster_chef/server.rb,
lib/cluster_chef/volume.rb,
lib/cluster_chef/cluster.rb,
lib/cluster_chef/compute.rb,
lib/cluster_chef/discovery.rb,
lib/cluster_chef/discovery.rb,
lib/cluster_chef/fog_layer.rb,
lib/cluster_chef/deprecated.rb,
lib/cluster_chef/dsl_object.rb,
lib/cluster_chef/private_key.rb,
lib/cluster_chef/server_slice.rb,
lib/cluster_chef/security_group.rb,
lib/cluster_chef/role_implications.rb

Overview

OK so things get a little fishy here, and it's all Opscode's fault ;-)

There's currently no API for setting ACLs. However, if the *client the node will run as* is the *client that creates the node*, it is granted the correct permissions.

  • client exists, node exists: don't need to do anything. We trust that permissions are correct.

  • client absent, node exists: client created, node is fine. We trust that permissions are correct.

  • client absent, node absent: client created, so have key; client creates node, so it has write permissions.

  • client exists, node absent: FAIL.

The current implementation persists the client keys locally to your Chef::Config. This is insecure and unmanageable; and the node will shortly re-register the key, making it invalide anyway.

If the client's private_key is empty/wrong and the node is absent, it will cause an error. in that case, you can:

  • create the node yourself in the management console, and grant access to its eponymous client; OR

  • nuke the client key from orbit (it's the only way to be sure) and re-run, taking all responsibility for the catastrophic results of an errant nuke; OR

  • wait for opscode to open API access for ACLs.

Defined Under Namespace

Modules: Cloud, DryRunnable Classes: ChefClientKey, Cluster, ComputeBuilder, DataBagKey, DslObject, Ec2Keypair, Facet, PrivateKey, RaidGroup, Server, ServerSlice, Volume

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.chef_configObject


49
# File 'lib/cluster_chef.rb', line 49

def self.chef_config()    @chef_config      ; end

.chef_config=(cc) ⇒ Object


48
# File 'lib/cluster_chef.rb', line 48

def self.chef_config=(cc) @chef_config = cc ; end

.cluster(name, attrs = {}, &block) ⇒ Object

Defines a cluster with the given name.

Examples:

ClusterChef.cluster 'demosimple' do
  cloud :ec2 do
    availability_zones  ['us-east-1d']
    flavor              "t1.micro"
    image_name          "ubuntu-natty"
  end
  role                  :base_role
  role                  :chef_client

  facet :sandbox do
    instances 2
    role                :nfs_client
  end
end

71
72
73
74
75
76
# File 'lib/cluster_chef.rb', line 71

def self.cluster(name, attrs={}, &block)
  name = name.to_sym
  cl = ( self.clusters[name] ||= ClusterChef::Cluster.new(name, attrs) )
  cl.configure(&block)
  cl
end

.cluster_filenamesHash

Map from cluster name to file name

Returns:

  • (Hash)

    map from cluster name to file name


104
105
106
107
108
109
110
111
112
113
114
# File 'lib/cluster_chef.rb', line 104

def self.cluster_filenames
  return @cluster_filenames if @cluster_filenames
  @cluster_filenames = {}
  cluster_path.each do |cp_dir|
    Dir[ File.join(cp_dir, '*.rb') ].each do |filename|
      cluster_name = File.basename(filename).gsub(/\.rb$/, '')
      @cluster_filenames[cluster_name] ||= filename
    end
  end
  @cluster_filenames
end

.cluster_pathObject

path to search for cluster definition files


31
32
33
34
35
36
37
# File 'lib/cluster_chef.rb', line 31

def self.cluster_path
  return Chef::Config[:cluster_path] if Chef::Config[:cluster_path]
  raise "Holy smokes, you have no cookbook_path or cluster_path set up. Follow chef's directions for creating a knife.rb." if Chef::Config[:cookbook_path].blank?
  cl_path = Chef::Config[:cookbook_path].map{|dir| File.expand_path('../clusters', dir) }.uniq
  ui.warn "No cluster path set. Taking a wild guess that #{cl_path.inspect} is \nreasonable based on your cookbook_path -- but please set cluster_path in your knife.rb"
  Chef::Config[:cluster_path] = cl_path
end

.clustersObject

Delegates


41
42
43
# File 'lib/cluster_chef.rb', line 41

def self.clusters
  Chef::Config[:clusters] ||= Mash.new
end

.die(*strings) ⇒ Object

Utility to die with an error message. If the last arg is an integer, use it as the exit code.


120
121
122
123
124
# File 'lib/cluster_chef.rb', line 120

def self.die *strings
  exit_code = strings.last.is_a?(Integer) ? strings.pop : -1
  strings.each{|str| ui.warn str }
  exit exit_code
end

.fetch_fog_volumesObject


162
163
164
165
# File 'lib/cluster_chef/discovery.rb', line 162

def self.fetch_fog_volumes
  Chef::Log.debug("Using fog to catalog all volumes")
  @fog_volumes = ClusterChef.fog_connection.volumes
end

.fog_addressesObject


152
153
154
155
156
# File 'lib/cluster_chef/discovery.rb', line 152

def self.fog_addresses
  return @fog_addresses if @fog_addresses
  Chef::Log.debug("Using fog to catalog all addresses")
  @fog_addresses = {}.tap{|hsh| ClusterChef.fog_connection.addresses.each{|fa| hsh[fa.public_ip] = fa } }
end

.fog_connectionObject


137
138
139
140
141
142
143
144
# File 'lib/cluster_chef/discovery.rb', line 137

def self.fog_connection
  @fog_connection ||= Fog::Compute.new({
      :provider              => 'AWS',
      :aws_access_key_id     => Chef::Config[:knife][:aws_access_key_id],
      :aws_secret_access_key => Chef::Config[:knife][:aws_secret_access_key],
      :region                => Chef::Config[:knife][:region]
    })
end

.fog_keypairsObject


167
168
169
170
171
# File 'lib/cluster_chef/discovery.rb', line 167

def self.fog_keypairs
  return @fog_keypairs if @fog_keypairs
  Chef::Log.debug("Using fog to catalog all keypairs")
  @fog_keypairs = {}.tap{|hsh| ClusterChef.fog_connection.key_pairs.each{|kp| hsh[kp.name] = kp } }
end

.fog_serversObject


146
147
148
149
150
# File 'lib/cluster_chef/discovery.rb', line 146

def self.fog_servers
  return @fog_servers if @fog_servers
  Chef::Log.debug("Using fog to catalog all servers")
  @fog_servers = ClusterChef.fog_connection.servers.all
end

.fog_volumesObject


158
159
160
# File 'lib/cluster_chef/discovery.rb', line 158

def self.fog_volumes
  @fog_volumes || fetch_fog_volumes
end

.load_cluster(cluster_name) ⇒ ClusterChef::Cluster

Return cluster if it's defined. Otherwise, search ClusterChef.cluster_path for an eponymous file, load it, and return the cluster it defines.

Raises an error if a matching file isn't found, or if loading that file doesn't define the requested cluster.

Returns:

Raises:

  • (ArgumentError)

86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/cluster_chef.rb', line 86

def self.load_cluster(cluster_name)
  raise ArgumentError, "Please supply a cluster name" if cluster_name.to_s.empty?
  return clusters[cluster_name] if clusters[cluster_name]

  cluster_file = cluster_filenames[cluster_name] or die("Couldn't find a definition for #{cluster_name} in cluster_path: #{cluster_path.inspect}")

  Chef::Log.info("Loading cluster #{cluster_file}")

  require cluster_file
  unless clusters[cluster_name] then  die("#{cluster_file} was supposed to have the definition for the #{cluster_name} cluster, but didn't") end

  clusters[cluster_name]
end

.safelyObject

Utility to turn an error into a warning

Examples:

ClusterChef.safely do
  ClusterChef.fog_connection.associate_address(self.fog_server.id, address)
end

134
135
136
137
138
139
140
141
142
# File 'lib/cluster_chef.rb', line 134

def self.safely
  begin
    yield
  rescue StandardError => boom
    ui.info( boom )
    Chef::Log.error( boom )
    Chef::Log.error( boom.backtrace.join("\n") )
  end
end

.uiObject


46
# File 'lib/cluster_chef.rb', line 46

def self.ui()    @ui      ; end

.ui=(ui) ⇒ Object


45
# File 'lib/cluster_chef.rb', line 45

def self.ui=(ui) @ui = ui ; end

Instance Method Details

#safely(*args, &block) ⇒ Object


173
174
175
# File 'lib/cluster_chef/discovery.rb', line 173

def safely *args, &block
  ClusterChef.safely(*args, &block)
end