lib/jamie.rb in jamie-0.1.0.alpha17 vs lib/jamie.rb in jamie-0.1.0.alpha18

- old
+ new

@@ -1,6 +1,22 @@ # -*- encoding: utf-8 -*- +# +# Author:: Fletcher Nichol (<fnichol@nichol.ca>) +# +# Copyright (C) 2012, Fletcher Nichol +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. require 'base64' require 'delegate' require 'digest' require 'erb' @@ -27,10 +43,12 @@ @source_root ||= Pathname.new(File.expand_path('../../', __FILE__)) end # Base configuration class for Jamie. This class exposes configuration such # as the location of the Jamie YAML file, instances, log_levels, etc. + # + # @author Fletcher Nichol <fnichol@nichol.ca> class Config attr_writer :yaml_file attr_writer :platforms attr_writer :suites @@ -95,10 +113,12 @@ end # Delegate class which adds the ability to find single and multiple # objects by their #name in an Array. Hey, it's better than monkey-patching # Array, right? + # + # @author Fletcher Nichol <fnichol@nichol.ca> class Collection < SimpleDelegator # Returns a single object by its name, or nil if none are found. # # @param name [String] name of object @@ -139,10 +159,11 @@ Suite.new(hash.rmerge(path_hash)) end def new_platform(hash) mpc = merge_platform_config(hash) + mpc['driver_config'] ||= Hash.new mpc['driver_config']['jamie_root'] = File.dirname(yaml_file) mpc['driver'] = new_driver(mpc['driver_plugin'], mpc['driver_config']) Platform.new(mpc) end @@ -218,10 +239,12 @@ end end # A Chef run_list and attribute hash that will be used in a convergence # integration. + # + # @author Fletcher Nichol <fnichol@nichol.ca> class Suite # @return [String] logical name of this suite attr_reader :name @@ -259,18 +282,20 @@ private def validate_options(opts) %w(name run_list).each do |k| - raise ArgumentError, "Attribute '#{attr}' is required." if opts[k].nil? + raise ArgumentError, "Attribute '#{k}' is required." if opts[k].nil? end end end # A target operating system environment in which convergence integration # will take place. This may represent a specific operating system, version, # and machine architecture. + # + # @author Fletcher Nichol <fnichol@nichol.ca> class Platform # @return [String] logical name of this platform attr_reader :name @@ -305,18 +330,20 @@ private def validate_options(opts) %w(name driver).each do |k| - raise ArgumentError, "Attribute '#{attr}' is required." if opts[k].nil? + raise ArgumentError, "Attribute '#{k}' is required." if opts[k].nil? end end end # An instance of a suite running on a platform. A created instance may be a # local virtual machine, cloud instance, container, or even a bare metal # server, which is determined by the platform's driver. + # + # @author Fletcher Nichol <fnichol@nichol.ca> class Instance # @return [Suite] the test suite configuration attr_reader :suite @@ -329,10 +356,12 @@ # Creates a new instance, given a suite and a platform. # # @param suite [Suite] a suite # @param platform [Platform] a platform def initialize(suite, platform) + validate_options(suite, platform) + @suite = suite @platform = platform @jr = Jr.new(@suite.name) end @@ -438,10 +467,15 @@ destroy if destroy_mode == :always end private + def validate_options(suite, platform) + raise ArgumentError, "Attribute 'suite' is required." if suite.nil? + raise ArgumentError, "Attribute 'platform' is required." if platform.nil? + end + def transition_to(desired) FSM.actions(last_action, desired).each do |transition| send("#{transition}_action") end end @@ -515,10 +549,12 @@ load_state['last_action'] end # The simplest finite state machine pseudo-implementation needed to manage # an Instance. + # + # @author Fletcher Nichol <fnichol@nichol.ca> class FSM # Returns an Array of all transitions to bring an Instance from its last # reported transistioned state into the desired transitioned state. # @@ -553,10 +589,12 @@ end # Command string generator to interface with Jamie Runner (jr). The # commands that are generated are safe to pass to an SSH command or as an # unix command argument (escaped in single quotes). + # + # @author Fletcher Nichol <fnichol@nichol.ca> class Jr # Constructs a new jr command generator, given a suite name. # # @param [String] suite_name name of suite on which to operate @@ -709,10 +747,12 @@ end end # Mixin that wraps a command shell out invocation, providing a #run_command # method. + # + # @author Fletcher Nichol <fnichol@nichol.ca> module ShellOut # Wrapped exception for any interally raised shell out commands. class ShellCommandFailed < StandardError ; end @@ -762,10 +802,12 @@ end # Base class for a driver. A driver is responsible for carrying out the # lifecycle activities of an instance, such as creating, converging, and # destroying an instance. + # + # @author Fletcher Nichol <fnichol@nichol.ca> class Base include ShellOut def initialize(config) @@ -840,10 +882,12 @@ # Base class for a driver that uses SSH to communication with an instance. # A subclass must implement the following methods: # * #create(instance, state) # * #destroy(instance, state) + # + # @author Fletcher Nichol <fnichol@nichol.ca> class SSHBase < Base def create(instance, state) raise NotImplementedError, "#create must be implemented by subclass." end @@ -971,9 +1015,11 @@ end end # Uploads Chef asset files such as dna.json, data bags, and cookbooks to an # instance over SSH. + # + # @author Fletcher Nichol <fnichol@nichol.ca> class ChefDataUploader include ShellOut def initialize(instance, ssh_args, jamie_root, chef_home)