#!/usr/bin/env ruby # # Author: cary@rightscale.com # Copyright 2014 RightScale, Inc. # # 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. # # Example: # bundle exec bin/organize preview demo/deployments.json --deployment-regexps="ec2:Name=([a-z]+)-([a-z])-([a-z]+)[0-9]+" --name-regexps="ec2:Name=[a-z]+-[a-z]-([a-z]+[0-9]+)" # # To better view results: # # > cd demo # > ./start_server # # Then point your browser to http://localhost:8000/ # require 'rubygems' require 'thor' require 'right_api_helper' class OrganizeApp < Thor desc "preview FILE", "generate an organization preview and output to JSON file." option :deployment_regexps, :required => true option :prefix option :name_regexps option :debug, :type => :boolean option :clear_cache, :type => :boolean def preview(filename) # setup setup_logging(options[:debug]) initialize_api_client setup_cache_objects(options[:clear_cache]) # organize result_hash = organize_by_tags( get_tag_array(options[:deployment_regexps]), get_tag_array(options[:name_regexps]), options[:prefix] ) # write results to a file json = JSON.pretty_generate(result_hash) @log.debug "JSON: #{json}" File.open(filename, "w") { |f| f.write(json)} @log.info("Done. Results written to '#{filename}'") end private def setup_logging(debug) @log = Logger.new(STDOUT) @log.formatter = proc do |severity, datetime, progname, msg| "#{msg}\n" end @log.level = Logger::INFO @log.level = Logger::DEBUG if debug end def initialize_api_client session = RightApiHelper::Session.new session.logger(@log) @client ||= session.create_client_from_file("~/.right_api_client/login.yml") end def setup_cache_objects(clear=false) @cache_dir = File.join(".", "cache") @instance_cache ||= RightApiHelper::Cache.new("instances", @cache_dir) @tag_cache ||= RightApiHelper::Cache.new("tags", @cache_dir) if clear @instance_cache.clear ; @tag_cache.clear FileUtils.rmdir(@cache_dir) end FileUtils.mkdir(@cache_dir) unless File.directory?(@cache_dir) end def get_tag_array(option) array = [] array = option.split(",") if option array end def instance_helper @helper ||= RightApiHelper::Instances.new(@client) @helper.logger(@log) @helper end # organize into groups based on tags # # All instances who's captures match all deployment_regexps will be grouped # together. The name of the group can be affected by passing in name_regexps and prefix. # # Array : deployment_regexps : list of namespace:key=value_regex values # # Returns: String : JSON object containing instances grouped by deployment_regexps def organize_by_tags(deployment_regexps, name_regexps=[], prefix="") @log.debug "ORGANIZE PARAMS: deployment_regexps: #{deployment_regexps} name_regexps: #{name_regexps}, prefix: #{prefix}" output_hash = {} # cached API queries for instances instances_by_href = query_instances # uncached tags query instance_hrefs = instances_by_href.keys @log.info "Querying tags from RightScale API..." @log.debug "instance_hrefs: #{instance_hrefs.inspect}" tag_data = @client.tags.by_resource(:resource_hrefs => instance_hrefs) tag_data.each do |tag| resources = tag.resource.is_a?(Array) ? tag.resource : [tag.resource] resources.each do |resource| tags = tag.tags.map{|t| t["name"]} href = resource.href relevant_tags_key= gather_relevant_tags(deployment_regexps, tags) new_name = gather_relevant_tags(name_regexps, tags) if name_regexps unless relevant_tags_key.empty? instance_name = (new_name.nil? || new_name.empty?) ? instances_by_href[href] : new_name instance_hash = {"href" => href, "type" => "Instance", "name" => instance_name} output_hash[relevant_tags_key] ||= {"name" => "#{prefix}#{relevant_tags_key}", "children" => []} output_hash[relevant_tags_key]["children"] << instance_hash end end end deployments_hash = { "deployments" => [] } output_hash.each do |deployment_type, deployment_data| deployments_hash["deployments"] << deployment_data end deployments_hash end # query instance data # # Use local cachefile to improve performance # def query_instances instances_by_href = {} if (instances_by_href = @instance_cache.get) == nil @log.info "Querying instances from RightScale API (might take a few minutes)..." instances = instance_helper.get_unmanaged_instances instances_by_href = instances.inject({}) {|new_hash, instance| instance.show ; new_hash[instance.href] = existing_name(instance); new_hash} @instance_cache.set(instances_by_href) end @log.debug "instances_by_href: #{instances_by_href.inspect}" instances_by_href end def existing_name(instance) if instance.respond_to?(:name) instance.name elsif instance.respond_to?(:resource_uid) instance.resource_uid else "unknown" end end def gather_relevant_tags(tag_regexps, tags, delimiter = '-') return_tags = [] tag_regexps.each do |regexp_str| regexp = Regexp.new(regexp_str) match_data = nil tags.detect{|t| match_data = regexp.match(t)} return_tags += match_data.captures if match_data end return_tags.flatten.join(delimiter) end def client @client ||= RightApi::Client.new(YAML.load_file(File.expand_path('~/.right_api_client/login.yml', __FILE__))) end end params = OrganizeApp.start(ARGV)