Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first commit

  • Loading branch information...
commit 56e72b9dbc1ae10ae8db735fb74e7872567ffc95 0 parents
Benjamin Black authored
201 LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.
0  README
No changes.
3  README.rdoc
@@ -0,0 +1,3 @@
+== opscode-agent
+
+A gem that provides...
61 Rakefile
@@ -0,0 +1,61 @@
+require 'rubygems'
+require 'rake/gempackagetask'
+require 'rubygems/specification'
+require 'date'
+require 'spec/rake/spectask'
+
+GEM = "opscode-agent"
+GEM_VERSION = "0.0.1"
+AUTHOR = "Benjamin Black"
+EMAIL = "bb@opscode.com"
+HOMEPAGE = "http://opscode.com/chef"
+SUMMARY = "Opscode node-local agent for systems management."
+
+spec = Gem::Specification.new do |s|
+ s.name = GEM
+ s.version = GEM_VERSION
+ s.platform = Gem::Platform::RUBY
+ s.has_rdoc = true
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
+ s.summary = SUMMARY
+ s.description = s.summary
+ s.author = AUTHOR
+ s.email = EMAIL
+ s.homepage = HOMEPAGE
+
+ # Uncomment this to add a dependency
+ # s.add_dependency "foo"
+
+ s.bindir = "bin"
+ s.executables = %w( opscode-agent )
+
+
+ s.require_path = 'lib'
+ s.autorequire = GEM
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
+end
+
+task :default => :spec
+
+desc "Run specs"
+Spec::Rake::SpecTask.new do |t|
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.spec_opts = %w(-fs --color)
+end
+
+
+Rake::GemPackageTask.new(spec) do |pkg|
+ pkg.gem_spec = spec
+end
+
+desc "install the gem locally"
+task :install => [:package] do
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
+end
+
+desc "create a gemspec file"
+task :make_spec do
+ File.open("#{GEM}.gemspec", "w") do |file|
+ file.puts spec.to_ruby
+ end
+end
0  TODO
No changes.
63 bin/opscode-agent
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+#
+# Author:: Benjamin Black (<bb@opscode.com>)
+# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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.
+#
+# NOTICE: This code is based on nanite-admin from the EY nanite project.
+
+# To work without being installed as a gem:
+libdir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
+$:.unshift libdir unless $:.include? libdir
+
+require 'rubygems'
+require 'nanite'
+require 'eventmachine'
+require 'thin'
+require 'opscode/agent/config'
+require 'opscode/agent/cli'
+require 'opscode/agent/http_service'
+
+# IMPORTANT!
+# You need raggi's patched async version of Thin at the moment to use
+# the nanite-admin tool.
+#
+# raggi's Git repo contains a branch called 'async_for_rack' which contains the
+# version of Thin you want to install. raggi has apparently removed the 'master'
+# branch of his Git repo so you may see a warning like that shown below.
+#
+# git clone git://github.com/raggi/thin.git thin-raggi-async
+# ...
+# warning: remote HEAD refers to nonexistent ref, unable to checkout. <<== IGNORE THIS
+#
+# cd thin-raggi-async/
+# git checkout --track -b async_for_rack origin/async_for_rack
+# warning: You appear to be on a branch yet to be born. <<== IGNORE THIS
+# warning: Forcing checkout of origin/async_for_rack. <<== IGNORE THIS
+# Branch async_for_rack set up to track remote branch refs/remotes/origin/async_for_rack.
+# Switched to a new branch "async_for_rack"
+
+# run : 'rake install' to build and install the Thin gem
+# cd <OPSCODE-AGENT>
+# ./bin/opscode-agent
+
+# When you need to update this Thin install you should be able to do a 'git pull' on the
+# "async_for_rack" branch.
+
+EM.run do
+ agent = Opscode::Agent::CLI.new
+ agent.run
+ Rack::Handler::Thin.run Opscode::Agent::HttpService.new(agent), :Port => 8000
+end
64 lib/opscode/actors/chef_actor.rb
@@ -0,0 +1,64 @@
+require 'json'
+require 'chef'
+require 'chef/client'
+require 'chef/runner'
+require 'chef/resource_collection'
+require 'stringio'
+require 'opscode/agent/config'
+
+module Opscode
+ class ChefActor
+ include Nanite::Actor
+
+ expose :collection, :resource, :recipe, :converge
+
+ def log_to_string(&block)
+ output = StringIO.new
+ Chef::Log.init(output)
+ block.call
+ output.string
+ end
+
+ def collection(payload)
+ log_to_string do
+ node = Chef::Client.new.build_node
+ resource_collection = JSON.parse(payload)
+ runner = Chef::Runner.new(node, resource_collection)
+ runner.converge
+ end
+ end
+
+ def resource(payload)
+ log_to_string do
+ collection = Chef::ResourceCollection.new()
+ collection << JSON.parse(payload)
+ node = Chef::Client.new.build_node
+ runner = Chef::Runner.new(node, collection)
+ runner.converge
+ end
+ end
+
+ def recipe(payload)
+ log_to_string do
+ collection = Chef::ResourceCollection.new()
+ collection << JSON.parse(payload)
+ client = Chef::Client.new
+ client.build_node
+ client.register
+ client.authenticate
+ client.sync_library_files
+ client.sync_attribute_files
+ client.sync_definitions
+ client.sync_recipes
+ client.converge
+ end
+ end
+
+ def converge(payload)
+ log_to_string do
+ client = Chef::Client.new
+ client.run
+ end
+ end
+ end
+end
55 lib/opscode/actors/ohai_actor.rb
@@ -0,0 +1,55 @@
+require 'json'
+require 'ohai'
+require 'opscode/agent/config'
+
+module Opscode
+ class OhaiActor
+ include Nanite::Actor
+
+ expose :index
+
+ @@ohai = nil
+
+ def initialize
+ @@ohai = Ohai::System.new
+ @@ohai.all_plugins
+
+ schedule = Opscode::Agent::Config[:schedule]
+ schedule.keys.each do |path|
+ EM.add_periodic_timer(schedule[path]) {@@ohai.refresh_plugins(path)}
+ end
+ end
+
+ def index(payload)
+ paths = JSON.parse(payload)
+ res = Mash.new
+ paths.each do |path|
+ parts = path.split("/"); parts.shift if parts[0].length == 0
+ res[path] = ohai_walk(parts, false)
+ end
+ res
+ end
+
+ def ohai_walk(path, refresh)
+ @@ohai.refresh_plugins(path.join('/')) if refresh
+ unless path[0]
+ @@ohai.json_pretty_print
+ else
+ ohai_walk_r(@@ohai, path)
+ end
+ end
+
+ def ohai_walk_r(ohai, path)
+ hop = (ohai.is_a?(Array) ? path.shift.to_i : path.shift)
+ if ohai[hop]
+ if path[0]
+ ohai_walk_r(ohai[hop], path)
+ else
+ ohai[hop].to_json
+ end
+ else
+ nil
+ end
+ end
+ end
+end
91 lib/opscode/agent/cli.rb
@@ -0,0 +1,91 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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 'rubygems'
+require 'nanite'
+require 'optparse'
+
+module Opscode
+ module Agent
+ class CLI
+
+ attr_accessor :config
+
+ def initialize(argv=ARGV)
+ load_args(argv)
+ end
+
+ def default_opts(opts, argv)
+ opts.banner = "Usage: #{$0} (options)"
+ opts.on("-c CONFIG", "--config CONFIG", "The agent config file to use") do |c|
+ @config[:config_file] = c
+ end
+ opts.on("-l LEVEL", "--loglevel LEVEL", "Set the log level (debug, info, warn, error, fatal)") do |l|
+ @config[:log_level] = l
+ end
+ opts.on("-L LOGLOCATION", "--logfile LOGLOCATION", "Set the log file location, defaults to STDOUT - recommended for daemonizing") do |lf|
+ @config[:log_location] = lf
+ end
+ opts.on("--nanite-host HOST", "The nanite exchange host") do |n|
+ @config[:host] = n
+ end
+ opts.on("--nanite-user USER", "The nanite user name") do |n|
+ @config[:user] = n
+ end
+ opts.on("--nanite-pass PASS", "The nanite password") do |p|
+ @config[:pass] = p
+ end
+ opts.on("--nanite-vhost VHOST", "The nanite vhost") do |v|
+ @config[:vhost] = v
+ end
+ opts.on("-d", "--daemonize", "Run the agent daemonized") do
+ @config[:daemonize] = true
+ end
+ opts.on_tail("-h", "--help", "Show this message") do
+ puts opts
+ exit 0
+ end
+ opts.parse!(argv)
+ end
+
+ def load_args(argv)
+ @config = {
+ :root => File.expand_path(File.join(File.dirname(__FILE__), '..')),
+ :host => Opscode::Agent::Config[:nanite_host],
+ :user => Opscode::Agent::Config[:nanite_user],
+ :pass => Opscode::Agent::Config[:nanite_pass],
+ :vhost => Opscode::Agent::Config[:nanite_vhost],
+ :daemonize => Opscode::Agent::Config[:daemonize],
+ :name => Opscode::Agent::Config[:name]
+ }
+ $0 = "#{@config[:name]} #{argv.join(' ')}\0"
+ opts = OptionParser.new do |opts|
+ default_opts(opts, argv)
+ end
+ end
+
+ def run
+ EM.run do
+ agent = Nanite::Agent.start(@config)
+ agent.register(Opscode::OhaiActor.new, 'state')
+ agent.register(Opscode::ChefActor.new, 'control')
+ agent.send :advertise_services
+ end
+ end
+ end
+ end
+end
41 lib/opscode/agent/config.rb
@@ -0,0 +1,41 @@
+#
+# Author:: Benjamin Black (<bb@opscode.com>)
+# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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 'opscode/mixin/config'
+
+module Opscode
+ module Agent
+ class Config
+ @configuration = {
+ :name => 'opscode-agent',
+ :daemonize => false,
+ :nanite_host => 'localhost',
+ :nanite_user => 'nanite',
+ :nanite_pass => 'testing',
+ :nanite_vhost => '/nanite',
+ :nanite_token => nil,
+ :schedule => {
+ "/network/interfaces" => 5,
+ "/" => 86400
+ }
+ }
+
+ include Opscode::Mixin::Config
+ end
+ end
+end
79 lib/opscode/agent/http_service.rb
@@ -0,0 +1,79 @@
+#
+# Author:: Benjamin Black (<bb@opscode.com>)
+# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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.
+#
+# NOTICE: This code is based in part on nanite-admin from the EY nanite project.
+
+require 'rack'
+require 'nanite'
+require 'opscode/actors/ohai_actor'
+require 'opscode/actors/chef_actor'
+
+module Opscode
+ module Agent
+ class HttpService
+
+ def initialize(agent)
+ @agent = agent
+ @ohai = OhaiActor.new
+ @chef = ChefActor.new
+ end
+
+ def call(env)
+ req = Rack::Request.new(env)
+ status = 200
+ content = nil
+ content_type = "application/json"
+
+ if env["REQUEST_METHOD"].eql?("GET") && (path = env["PATH_INFO"].split("/")).length > 1
+ case path[1]
+ when "state"
+ rparams = Rack::Utils::parse_query(Rack::Utils::unescape(req.query_string))
+ refresh = (rparams["refresh"] && rparams["refresh"].downcase.eql?("true"))
+ path.shift; path.shift
+ content = @ohai.ohai_walk(path, refresh)
+ when "control"
+ rparams = Rack::Utils::parse_query(Rack::Utils::unescape(req.query_string))
+ rparams ||= Hash.new
+ path.shift; path.shift
+
+ output = nil
+
+ case path[0]
+ when "collection"
+ output = @chef.collection(rparams)
+ when "resource"
+ output = @chef.resource(rparams)
+ when "recipe"
+ output = @chef.recipe(rparams)
+ when "converge"
+ output = @chef.converge(rparams)
+ end
+
+ content_type = "text/plain"
+ content = output
+ end
+ unless content
+ status = 404
+ content = "Unknown path"
+ end
+ end
+
+ [status, { 'Content-Type' => content_type }, content.to_s]
+ end
+ end
+ end
+end
2  lib/opscode/config.yml
@@ -0,0 +1,2 @@
+---
+:identity: 8fae8f214df2ce0a05eb23a2d7a9d757
113 lib/opscode/mixin/config.rb
@@ -0,0 +1,113 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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 'opscode/mixin/from_file'
+
+module Opscode
+ module Mixin
+ module Config
+
+ def self.included(base)
+ base.class_eval do
+ extend ClassMethods
+ end
+ end
+
+ module ClassMethods
+ include Opscode::Mixin::FromFile
+
+ # Pass Opscode::Mixin::Config.configure() a block, and it will yield @configuration.
+ #
+ # === Parameters
+ # <block>:: A block that takes @configure as it's argument
+ def configure(&block)
+ yield @configuration
+ end
+
+ # Get the value of a configuration option
+ #
+ # === Parameters
+ # config_option<Symbol>:: The configuration option to return
+ #
+ # === Returns
+ # value:: The value of the configuration option
+ #
+ # === Raises
+ # <ArgumentError>:: If the configuration option does not exist
+ def [](config_option)
+ if @configuration.has_key?(config_option.to_sym)
+ @configuration[config_option.to_sym]
+ else
+ raise ArgumentError, "Cannot find configuration option #{config_option.to_s}"
+ end
+ end
+
+ # Set the value of a configuration option
+ #
+ # === Parameters
+ # config_option<Symbol>:: The configuration option to set (within the [])
+ # value:: The value for the configuration option
+ #
+ # === Returns
+ # value:: The new value of the configuration option
+ def []=(config_option, value)
+ @configuration[config_option.to_sym] = value
+ end
+
+ # Check if Opscode::Mixin::Config has a configuration option.
+ #
+ # === Parameters
+ # key<Symbol>:: The configuration option to check for
+ #
+ # === Returns
+ # <True>:: If the configuration option exists
+ # <False>:: If the configuration option does not exist
+ def has_key?(key)
+ @configuration.has_key?(key.to_sym)
+ end
+
+ # Allows for simple lookups and setting of configuration options via method calls
+ # on Opscode::Mixin::Config. If there any arguments to the method, they are used to set
+ # the value of the configuration option. Otherwise, it's a simple get operation.
+ #
+ # === Parameters
+ # method_symbol<Symbol>:: The method called. Must match a configuration option.
+ # *args:: Any arguments passed to the method
+ #
+ # === Returns
+ # value:: The value of the configuration option.
+ #
+ # === Raises
+ # <ArgumentError>:: If the method_symbol does not match a configuration option.
+ def method_missing(method_symbol, *args)
+ if @configuration.has_key?(method_symbol)
+ if args.length == 1
+ @configuration[method_symbol] = args[0]
+ elsif args.length > 1
+ @configuration[method_symbol] = args
+ end
+ return @configuration[method_symbol]
+ else
+ raise ArgumentError, "Cannot find configuration option #{method_symbol.to_s}"
+ end
+ end
+
+ end # class << self
+ end
+ end
+end
36 lib/opscode/mixin/from_file.rb
@@ -0,0 +1,36 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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.
+#
+
+module Opscode
+ module Mixin
+ module FromFile
+
+ # Loads a given ruby file, and runs instance_eval against it in the context of the current
+ # object.
+ #
+ # Raises an IOError if the file cannot be found, or is not readable.
+ def from_file(filename)
+ if File.exists?(filename) && File.readable?(filename)
+ self.instance_eval(IO.read(filename), filename, 1)
+ else
+ raise IOError, "Cannot open or read #{filename}!"
+ end
+ end
+ end
+ end
+end
14 script/destroy
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/destroy'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:newgem_simple, :test_unit]
+RubiGen::Scripts::Destroy.new.run(ARGV)
14 script/generate
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/generate'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:newgem_simple, :test_unit]
+RubiGen::Scripts::Generate.new.run(ARGV)
7 spec/opscode-agent_spec.rb
@@ -0,0 +1,7 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe "opscode-agent" do
+ it "should do nothing" do
+ true.should == true
+ end
+end
2  spec/spec_helper.rb
@@ -0,0 +1,2 @@
+$TESTING=true
+$:.push File.join(File.dirname(__FILE__), '..', 'lib')
Please sign in to comment.
Something went wrong with that request. Please try again.