├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── Gemfile ├── README.md ├── Rakefile ├── bin ├── console ├── pec └── setup ├── exe └── pec ├── lib ├── pec.rb └── pec │ ├── cli.rb │ ├── command.rb │ ├── command │ ├── base.rb │ ├── config.rb │ ├── destroy.rb │ ├── halt.rb │ ├── hosts.rb │ ├── init.rb │ ├── list.rb │ ├── status.rb │ └── up.rb │ ├── config_error.rb │ ├── config_file.rb │ ├── configure.rb │ ├── core.rb │ ├── handler.rb │ ├── handler │ ├── availability_zone.rb │ ├── flavor.rb │ ├── image.rb │ ├── keypair.rb │ ├── networks.rb │ ├── networks │ │ ├── allowed_address_pairs.rb │ │ └── ip_address.rb │ ├── templates.rb │ ├── user_data.rb │ └── user_data │ │ ├── nic.rb │ │ └── nic │ │ ├── base.rb │ │ ├── rhel.rb │ │ └── ubuntu.rb │ ├── init.rb │ ├── logger.rb │ ├── port_error.rb │ ├── sample.rb │ └── version.rb ├── pec.gemspec └── spec ├── fixture ├── basic_config.yaml ├── erb_basic_config.yaml.erb ├── erb_include_config.yaml.erb ├── include_config.yaml ├── redhat_single_instance.yaml ├── ubuntu_single_instance.yaml └── user_data_template.yaml ├── lib ├── command │ ├── config_spec.rb │ ├── destroy_spec.rb │ ├── halt_spec.rb │ ├── status_spec.rb │ └── up_spec.rb ├── configure_spec.rb └── handler │ ├── keypair_spec.rb │ ├── networks_spec.rb │ ├── templates_spec.rb │ └── user_data_spec.rb ├── spec_helper.rb └── support └── nic_helper.rb /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | /vendor 11 | /*.yaml 12 | /*.erb 13 | *.sample 14 | /user_datas 15 | .ruby-version 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.6 4 | - 2.2.2 5 | addons: 6 | code_climate: 7 | repo_token: c969d1896316cbd26ab70d3b7fef4f4e168df83b849fa7f16a1885569c86f29c 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in pec.gemspec 4 | gemspec 5 | gem "codeclimate-test-reporter", group: :test, require: nil 6 | gem 'json', github: 'flori/json', branch: 'v1.8' 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pec 2 | [![Build Status](https://travis-ci.org/yaocloud/pec.svg?branch=v0.7.7)](https://travis-ci.org/yaocloud/pec) 3 | [![Code Climate](https://codeclimate.com/github/pyama86/pec/badges/gpa.svg)](https://codeclimate.com/github/pyama86/pec) 4 | [![Test Coverage](https://codeclimate.com/github/pyama86/pec/badges/coverage.svg)](https://codeclimate.com/github/pyama86/pec/coverage) 5 | 6 | OpenStack Vm create wrapper 7 | 8 | ## Install 9 | 10 | $ gem install pec 11 | 12 | ## Usage 13 | # set up 14 | $ pec init 15 | 16 | ``` 17 | create - /Pec.yaml 18 | create - /user_data/web_server.yaml.sample 19 | ``` 20 | 21 | $ pec up ... 22 | 23 | $ pec destroy ... 24 | 25 | $ pec halt ... 26 | 27 | $ pec status ... 28 | 29 | $ pec list 30 | 31 | $ pec hosts 32 | 33 | $ pec config ... 34 | 35 | ### Configure 36 | #### Pec.yaml or Pec.yaml.erb 37 | support format yaml,erb 38 | ``` 39 | # merge of yaml 40 | _default_: &def 41 | os_type: centos 42 | tenant: your_tenant 43 | tenant_id: your_tenan_id(using a member roll) 44 | image: centos-7.1_chef-12.3_puppet-3.7 45 | flavor: m1.small 46 | availability_zone: nova 47 | 48 | # vm config 49 | pyama-test001: 50 | <<: *def 51 | networks: 52 | eth0: 53 | bootproto: static 54 | allowed_address_pairs: 55 | - 10.1.1.5/24 56 | ip_address: 10.1.1.1/24 57 | gateway: 10.1.1.254 58 | dns1: 8.8.8.8 59 | dns2: 8.8.8.8 60 | eth1: 61 | bootproto: dhcp 62 | security_group: 63 | - default 64 | - ssh 65 | templates: 66 | - base.yaml 67 | - webserver.yaml 68 | user_data: 69 | hostname: pyama-test001 70 | fqdn: pyama-test001.ikemen.com 71 | repo_releasever: 7.1.1503 72 | pyama-test002: 73 | <<: *def 74 | ・・・ 75 | 76 | # include config 77 | includes: 78 | - path/to/a.yaml 79 | - path/to/b.yaml.erb 80 | 81 | ``` 82 | ##### Detail 83 | 84 | | column | require | value | 85 | | ----------------- | ------- | ------------------------------- | 86 | | instance_name | ○ | pyama-test001* | 87 | | tenant | ○ | your_tenant | 88 | | image | ○ | centos-7.1_chef-12.3_puppet-3.7 | 89 | | flavor | ○ | m1.small | 90 | | os_type | - | centos(centos or ubuntu | 91 | | networks | - | [] | 92 | | security_group | - | [default,ssh] | 93 | | templates | - | [base.yaml,webserver.yaml] | 94 | | user_data | - | - | 95 | | availability_zone | - | nova | 96 | 97 | * it begins with `_` instance name is yaml merge template 98 | 99 | ##### Networks 100 | | column | require | value | 101 | | --------------------- | --------| ---------------------------------------------------------- | 102 | | bootproto | ○ | static or dhcp | 103 | | ip_address | ※ | 10.1.1.1/24 | 104 | | path | | default:/etc/sysconfig/network-scripts/ifcfg-[device_name] | 105 | | allowed_address_pairs | | [10.1.1.2/24] | 106 | 107 | ※ bootproto=static is required 108 | 109 | Items other than the above are output to the configuration file with `KEY = value` format 110 | 111 | #### Includes 112 | ```yaml 113 | # example 114 | includes: 115 | - path/to/a.yaml 116 | - path/to/b.yaml 117 | ``` 118 | 119 | Read order is this as 120 | 1.Pec.yaml 121 | 2.path/to/a.yaml 122 | 3.path/to/b.yaml 123 | 124 | ## Author 125 | * pyama86 126 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | ENV['CODECLIMATE_REPO_TOKEN'] = "c969d1896316cbd26ab70d3b7fef4f4e168df83b849fa7f16a1885569c86f29c" 4 | ENV['PEC_TEST'] = "test" 5 | RSpec::Core::RakeTask.new("spec") 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "pec" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/pec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pec' 3 | Pec::CLI.start 4 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | 5 | bundle install 6 | 7 | # Do any other automated setup that you need to do here 8 | -------------------------------------------------------------------------------- /exe/pec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pec' 3 | Pec::CLI.start 4 | -------------------------------------------------------------------------------- /lib/pec.rb: -------------------------------------------------------------------------------- 1 | require 'pp' 2 | require 'base64' 3 | require 'yao' 4 | require 'yaml' 5 | require 'thor' 6 | require 'ip' 7 | require 'colorator' 8 | require "pec/core" 9 | require "pec/config_file" 10 | require "pec/version" 11 | require "pec/logger" 12 | require "pec/configure" 13 | require "pec/handler" 14 | require "pec/command" 15 | require "pec/sample" 16 | require "pec/init" 17 | require "pec/cli" 18 | 19 | module Pec 20 | def self.init_yao(_tenant_name) 21 | return unless reload_yao?(_tenant_name) 22 | check_env 23 | Yao.configure do 24 | auth_url ENV["OS_AUTH_URL"] 25 | username ENV["OS_USERNAME"] 26 | password ENV["OS_PASSWORD"] 27 | tenant_name _tenant_name 28 | client_cert ENV['OS_CERT'] 29 | client_key ENV['OS_KEY'] 30 | region_name ENV['OS_REGION_NAME'] 31 | end 32 | end 33 | 34 | def self.reload_yao?(_tenant_name) 35 | @_last_tenant = _tenant_name if _tenant_name != @_last_tenant 36 | end 37 | 38 | def self.load_config(config_name="Pec.yaml") 39 | @_configure ||= [] 40 | ConfigFile.new(Pec.options[:config_file] || config_name).load.to_hash.reject {|k,v| k[0].match(/\_/) || k.match(/^includes$/) }.each do |config| 41 | @_configure << Pec::Configure.new(config) 42 | end 43 | rescue => e 44 | Pec::Logger.critical "configure error!" 45 | raise e 46 | end 47 | 48 | def self.configure 49 | load_config unless @_configure 50 | @_configure 51 | end 52 | 53 | def self.servers(filter_hosts, not_fetch) 54 | self.configure.each do |config| 55 | next if filter_hosts.size > 0 && filter_hosts.none? {|name| config.name.match(/^#{name}/)} 56 | Pec.init_yao(config.tenant) 57 | server = fetch_server(config) unless not_fetch 58 | yield(server, config) 59 | end 60 | end 61 | 62 | def self.fetch_server(config) 63 | server_list(config).find {|s|s.name == config.name} 64 | end 65 | 66 | def self.get_tenant_id 67 | Yao.current_tenant_id 68 | end 69 | 70 | def self.server_list(config) 71 | @_server_list ||= {} 72 | @_server_list[config.tenant] ||= Yao::Server.list_detail({ tenant_id: get_tenant_id }) 73 | end 74 | 75 | def self.flavor_list(server) 76 | @_flavor_list ||= {} 77 | @_flavor_list[server.tenant_id] ||= Yao::Flavor.list 78 | end 79 | 80 | def self.check_env 81 | %w( 82 | OS_AUTH_URL 83 | OS_USERNAME 84 | OS_PASSWORD 85 | ).each do |name| 86 | raise "please set env #{name}" unless ENV[name] 87 | end 88 | end 89 | 90 | def self.processor_matching(source, klass) 91 | source.keys.each do |k| 92 | Object.const_get(klass.to_s).constants.each do |c| 93 | object = Object.const_get("#{klass.to_s}::#{c}") 94 | yield object if k.to_s == object.kind.to_s 95 | end 96 | end 97 | end 98 | 99 | def self.config_reset 100 | %w( 101 | _configure 102 | _tenant_list 103 | _server_list 104 | _flavor_list 105 | ).each do |name| 106 | instance_variable_set("@#{name}".to_sym, nil) 107 | end 108 | end 109 | 110 | def self.options(opt=nil) 111 | @_opt ||= {} 112 | @_opt = opt if opt 113 | @_opt 114 | end 115 | end 116 | 117 | class ::Hash 118 | def deep_merge(second) 119 | merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 } 120 | self.merge(second.to_h, &merger) 121 | end 122 | 123 | def deep_merge!(second) 124 | self.merge!(deep_merge(second)) 125 | end 126 | end 127 | 128 | -------------------------------------------------------------------------------- /lib/pec/cli.rb: -------------------------------------------------------------------------------- 1 | require 'pec' 2 | module Pec 3 | class CLI < Thor 4 | class_option :config_file , type: :string, aliases: "-c" 5 | 6 | desc 'init', 'create sample config' 7 | def init 8 | _sub_command([], options) 9 | end 10 | 11 | desc 'up [HOSTNAME1, HOSTNAME2, ...]', 'vm create' 12 | def up(*filter_hosts) 13 | _sub_command(filter_hosts, options) 14 | end 15 | 16 | option :force , type: :boolean, aliases: "-f" 17 | desc "destroy [HOSTNAME1, HOSTNAME2, ...]", "delete vm" 18 | def destroy(*filter_hosts) 19 | _sub_command(filter_hosts, options) 20 | end 21 | 22 | desc "halt [HOSTNAME1, HOSTNAME2, ...]", "halt vm" 23 | def halt(*filter_hosts) 24 | _sub_command(filter_hosts, options) 25 | end 26 | 27 | desc "status [HOSTNAME1, HOSTNAME2, ...]", "vm status" 28 | def status(*filter_hosts) 29 | _sub_command(filter_hosts, options) 30 | end 31 | 32 | desc "list", "vm list" 33 | def list 34 | _sub_command([], options) 35 | end 36 | 37 | desc "config [HOSTNAME1, HOSTNAME2, ...]", "show configure" 38 | def config(*filter_hosts) 39 | _sub_command(filter_hosts, options) 40 | end 41 | 42 | desc "hosts", "/etc/hosts records" 43 | def hosts 44 | _sub_command([], options) 45 | end 46 | 47 | map %w[--version -v] => :__print_version 48 | desc "--version, -v", "print the version" 49 | def __print_version 50 | puts Pec::VERSION 51 | end 52 | 53 | no_commands do 54 | def _sub_command(filter_hosts, options) 55 | Pec.options options 56 | Object.const_get("Pec::Command::#{caller[0][/`([^']*)'/, 1].capitalize}").run(filter_hosts) 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/pec/command.rb: -------------------------------------------------------------------------------- 1 | module Pec 2 | module Command 3 | autoload :Base, "pec/command/base" 4 | autoload :Up, "pec/command/up" 5 | autoload :Destroy, "pec/command/destroy" 6 | autoload :Halt, "pec/command/halt" 7 | autoload :Status, "pec/command/status" 8 | autoload :Config, "pec/command/config" 9 | autoload :Init, "pec/command/init" 10 | autoload :List, "pec/command/list" 11 | autoload :Hosts, "pec/command/hosts" 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/pec/command/base.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class Base 3 | def self.run(filter_hosts) 4 | before_do 5 | Pec.servers(filter_hosts, not_fetch) do |server,config| 6 | task(server, config) 7 | end 8 | after_do 9 | rescue => e 10 | print_exception(e) 11 | end 12 | 13 | def self.print_exception(e) 14 | Pec::Logger.critical(e) 15 | Pec::Logger.info("\t" + e.backtrace.join("\n\t")) 16 | end 17 | 18 | def self.not_fetch; end 19 | def self.task(server, config); end 20 | def self.before_do; end 21 | def self.after_do; end 22 | 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/pec/command/config.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class Config < Base 3 | def self.task(server, config) 4 | puts YAML.dump(config.inspect[0] => config.inspect[1]) 5 | end 6 | 7 | def self.not_fetch 8 | true 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/pec/command/destroy.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class Destroy < Base 3 | def self.task(server, config) 4 | unless server 5 | Pec::Logger.notice "not be created #{config.name}" 6 | else 7 | if Pec.options[:force] || Thor.new.yes?("#{config.name}: Are you sure you want to destroy the '#{config.name}' VM? [y/N]") 8 | ports = Yao::Port.list({ device_id: server.id }) 9 | ports.each do |port| 10 | Yao::Port.destroy(port.id) 11 | Pec::Logger.notice "port delete id:#{port.id}" 12 | end if ports 13 | 14 | Yao::Server.destroy(server.id) 15 | Pec::Logger.info "#{config.name} is deleted!" 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/pec/command/halt.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class Halt < Base 3 | def self.task(server, config) 4 | case 5 | when server.nil? 6 | Pec::Logger.notice "not be created #{config.name}" 7 | when server.status != "ACTIVE" 8 | Pec::Logger.notice "#{config.name} server status is #{server.status} must be ACTIVE" 9 | else 10 | Yao::Server.shutoff(server.id) 11 | Pec::Logger.info "#{config.name} is halted!" 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/pec/command/hosts.rb: -------------------------------------------------------------------------------- 1 | require 'ipaddr' 2 | module Pec::Command 3 | class Hosts < Base 4 | def self.task(server, config) 5 | ip_addresses(server).each do |i| 6 | host_name = private_ip?(i) ? "#{config.name}.lan" : config.name 7 | puts sprintf( 8 | "%-15s %-35s", 9 | i, 10 | host_name, 11 | ) 12 | end if server 13 | end 14 | 15 | def self.ip_addresses(server) 16 | server.addresses.map do |ethers| 17 | ethers[1].map do |ether| 18 | ether["addr"] 19 | end 20 | end.flatten 21 | end 22 | 23 | def self.private_ip?(target) 24 | ::IPAddr.new("10.0.0.0/8").include?(target) || 25 | ::IPAddr.new("172.16.0.0/12").include?(target) || 26 | ::IPAddr.new("192.168.0.0/16").include?(target) 27 | end 28 | 29 | def self.before_do 30 | @_error = nil 31 | puts "# ------ #{Date.today.strftime("%Y%m%d%H%M%S")} pec add start ------" 32 | end 33 | 34 | def self.after_do 35 | m = "# " + ("-" * 16) 36 | n = ("-" * 17) 37 | puts m + " pec end " + n 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/pec/command/init.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class Init < Base 3 | def self.run(_null) 4 | Pec::Init.show_env_setting 5 | Pec::Init.create_template_dir 6 | Pec::Init.create_sample_config 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/pec/command/list.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class List < Base 3 | def self.task(server, config) 4 | puts sprintf( 5 | " %-35s", 6 | config.name 7 | ) 8 | end 9 | 10 | def self.before_do 11 | Thor.new.say("vm list:", :yellow) 12 | end 13 | 14 | def self.not_fetch 15 | true 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/pec/command/status.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class Status < Base 3 | def self.task(server, config) 4 | if server 5 | tenant_name = config.tenant 6 | flavor_name = safe_was_delete(config.name, config.flavor, :flavor) do 7 | fetch_flavor(server).name 8 | end 9 | puts sprintf( 10 | " %-35s %-10s %-10s %-10s %-10s %-10s %-35s %-48s", 11 | config.name, 12 | server.status, 13 | tenant_name, 14 | flavor_name, 15 | server.availability_zone, 16 | server.key_name, 17 | server.ext_srv_attr_host, 18 | ip_addresses(server) 19 | ) 20 | else 21 | puts sprintf(" %-35s %-10s", 22 | config.name, 23 | "uncreated" 24 | ) 25 | end 26 | end 27 | 28 | def self.fetch_flavor(server) 29 | Pec.flavor_list(server).find {|f|f.id == server.flavor['id']} 30 | end 31 | 32 | def self.ip_addresses(server) 33 | server.addresses.map do |ethers| 34 | ethers[1].map do |ether| 35 | ether["addr"] 36 | end 37 | end.flatten.join(",") 38 | end 39 | 40 | def self.before_do 41 | @_error = nil 42 | Pec::Logger.warning "Current machine status:" 43 | end 44 | 45 | def self.after_do 46 | Pec::Logger.warning @_error.join("\n") if @_error 47 | end 48 | 49 | def self.safe_was_delete(host_name, default ,resource_name, &blk) 50 | begin 51 | blk.call 52 | rescue 53 | @_error ||= [] 54 | @_error << "#{host_name}:#{resource_name} is unmatch id. may be id has changed" 55 | default 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/pec/command/up.rb: -------------------------------------------------------------------------------- 1 | module Pec::Command 2 | class Up < Base 3 | def self.task(server, config) 4 | case 5 | when server.nil? 6 | Pec::Logger.info "make start #{config.name}" 7 | attribute = {name: config.name} 8 | 9 | begin 10 | attribute = build(config, attribute) 11 | attribute = post_build(config, attribute) 12 | 13 | Yao::Server.create(attribute) 14 | Pec::Logger.info "create success! #{config.name}" 15 | rescue => e 16 | Pec::Logger.critical(e) 17 | Pec::Logger.warning "recovery start #{config.name}" 18 | 19 | attribute.deep_merge!(e.attribute) if e.is_a?(Pec::PortError) && e.attribute 20 | 21 | Pec.processor_matching(config, Pec::Handler) do |klass| 22 | klass.recover(attribute) 23 | end 24 | Pec::Logger.warning "recovery success! #{config.name}" 25 | end 26 | 27 | when server.status == "SHUTOFF" 28 | Yao::Server.start(server.id) 29 | Pec::Logger.info "start server: #{config.name}" 30 | else 31 | Pec::Logger.notice "already server: #{config.name}" 32 | end 33 | end 34 | 35 | class << self 36 | %i( 37 | build 38 | post_build 39 | ).each do |name| 40 | define_method(name) do |config,attribute| 41 | source = config 42 | input = [config] 43 | 44 | if name == :post_build 45 | source = attribute 46 | input = [config, attribute] 47 | end 48 | 49 | Pec.processor_matching(source, Pec::Handler) do |klass| 50 | if attr = klass.send(name, *input) 51 | attribute.deep_merge!(attr) 52 | end 53 | end 54 | attribute 55 | end 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/pec/config_error.rb: -------------------------------------------------------------------------------- 1 | class Pec::ConfigError < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /lib/pec/config_file.rb: -------------------------------------------------------------------------------- 1 | require 'erb' 2 | module Pec 3 | class ConfigFile 4 | attr_accessor :config_name 5 | def initialize(config_name) 6 | self.config_name = File.exist?("#{config_name}.erb") ? "#{config_name}.erb" : config_name 7 | end 8 | 9 | def load 10 | base = read_file(config_name) 11 | include_files = YAML.load(base).to_hash.find{|k,v| k.match(/^includes$/) && !v.nil? } 12 | inc = include_files ? include_files[1].map {|f| read_file(f)}.join("\n") : "" 13 | YAML.load(base + inc) 14 | end 15 | 16 | def read_file(file_name) 17 | if File.exist?(file_name) 18 | case 19 | when file_name.match(/.erb$/) 20 | erb = ERB.new(File.read(file_name), nil, '%-') 21 | erb.result 22 | when file_name.match(/.yaml$/) || file_name.match(/.yml$/) 23 | File.read(file_name) 24 | else 25 | raise "not match file type must be yaml or erb" 26 | end 27 | else 28 | raise " #{file_name} not exiets!" 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/pec/configure.rb: -------------------------------------------------------------------------------- 1 | require "pec/config_error" 2 | 3 | module Pec 4 | class Configure 5 | def initialize(config) 6 | validate(config) 7 | @_config = config 8 | end 9 | 10 | def inspect 11 | @_config 12 | end 13 | 14 | def name 15 | @_config[0] 16 | end 17 | 18 | def keys 19 | @_config[1].keys 20 | end 21 | 22 | def method_missing(method, *args) 23 | @_config[1][method.to_s] 24 | end 25 | 26 | def validate(config) 27 | %w( 28 | tenant 29 | image 30 | flavor 31 | networks 32 | ).each do |k| 33 | raise "#{config[0]}:host key #{k} is require" unless config[1][k] 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/pec/core.rb: -------------------------------------------------------------------------------- 1 | module Pec 2 | module Core 3 | attr_accessor :kind 4 | def build(*args) 5 | raise "#{self.class.name} not defined method build" 6 | end 7 | 8 | def post_build(*args); end 9 | 10 | def recover(*args); end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/pec/handler.rb: -------------------------------------------------------------------------------- 1 | module Pec 2 | module Handler 3 | autoload :AvailabilityZone, "pec/handler/availability_zone" 4 | autoload :Image, "pec/handler/image" 5 | autoload :Flavor, "pec/handler/flavor" 6 | autoload :Keypair, "pec/handler/keypair" 7 | autoload :Networks, "pec/handler/networks" 8 | autoload :UserData, "pec/handler/user_data" 9 | autoload :Templates, "pec/handler/templates" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/pec/handler/availability_zone.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class AvailabilityZone 3 | extend Pec::Core 4 | self.kind = 'availability_zone' 5 | 6 | def self.build(config) 7 | Pec::Logger.notice "availability_zone is #{config.availability_zone}" 8 | { 9 | availability_zone: config.availability_zone 10 | } 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/pec/handler/flavor.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class Flavor 3 | extend Pec::Core 4 | self.kind = 'image' 5 | 6 | def self.build(config) 7 | Pec::Logger.notice "flavor is #{config.flavor}" 8 | flavor_id = Yao::Flavor.list.find {|flavor| flavor.name == config.flavor}.id 9 | { 10 | flavorRef: flavor_id 11 | } 12 | rescue 13 | raise Pec::ConfigError, "flavor name=#{config.flavor} does not exist" 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/pec/handler/image.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class Image 3 | extend Pec::Core 4 | self.kind = 'image' 5 | 6 | def self.build(config) 7 | Pec::Logger.notice "image is #{config.image}" 8 | image_id = Yao::Image.list.find {|image| image.name == config.image}.id 9 | { 10 | imageRef: image_id 11 | } 12 | rescue 13 | raise Pec::ConfigError, "image name=#{config.image} does not exist" 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/pec/handler/keypair.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class Keypair 3 | extend Pec::Core 4 | self.kind = 'keypair' 5 | 6 | def self.build(config) 7 | return({}) unless config.keypair 8 | 9 | Pec::Logger.notice "keypair is #{config.keypair}" 10 | keypair = Yao::Keypair.list.find {|k| k.name == config.keypair } 11 | if keypair 12 | { 13 | key_name: keypair.name, 14 | } 15 | else 16 | raise Pec::ConfigError, "keypair name=#{config.keypair} does not exist" 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/pec/handler/networks.rb: -------------------------------------------------------------------------------- 1 | require "pec/port_error" 2 | module Pec::Handler 3 | class Networks 4 | extend Pec::Core 5 | self.kind = 'networks' 6 | autoload :IpAddress, "pec/handler/networks/ip_address" 7 | autoload :AllowedAddressPairs, "pec/handler/networks/allowed_address_pairs" 8 | 9 | class << self 10 | NAME = 0 11 | CONFIG = 1 12 | 13 | def build(config) 14 | ports = [] 15 | config.networks.each do |network| 16 | validate(network) 17 | Pec::Logger.notice "port create start : #{network[NAME]}" 18 | port = create_port(config, network) 19 | Pec::Logger.notice "assgin ip : #{port.fixed_ips.first["ip_address"]}" 20 | ports << port 21 | end 22 | { 23 | networks: ports.map {|port| { uuid: '', port: port.id }} 24 | } 25 | rescue Yao::Conflict => e 26 | raise(Pec::PortError.new(ports), e) 27 | end 28 | 29 | def recover(attribute) 30 | return unless attribute[:networks] 31 | 32 | Pec::Logger.notice "start port recovery" 33 | attribute[:networks].each do |port| 34 | if port[:port] 35 | Yao::Port.destroy(port[:port]) 36 | Pec::Logger.notice "port delete id:#{port[:port]}" 37 | end 38 | end 39 | Pec::Logger.notice "complete port recovery" 40 | end 41 | 42 | def validate(network) 43 | %w( 44 | bootproto 45 | ip_address 46 | ).each do |k| 47 | raise "network key #{k} is require" unless network[CONFIG][k] 48 | end 49 | end 50 | 51 | def create_port(config, network) 52 | attribute = gen_port_attribute(config, network) 53 | Yao::Port.create(attribute) 54 | end 55 | 56 | def gen_port_attribute(config, network) 57 | ip = IP.new(network[CONFIG]['ip_address']) 58 | subnet = Yao::Subnet.list.find {|s|s.cidr == ip.network.to_s} 59 | attribute = { 60 | name: network[NAME], 61 | network_id: subnet.network_id 62 | } 63 | 64 | attribute.merge!( 65 | security_group(config) 66 | ) if config.security_group 67 | 68 | Pec.processor_matching(network[CONFIG], Pec::Handler::Networks) do |klass| 69 | ops = klass.build(network) 70 | attribute.deep_merge!(ops) if ops 71 | end 72 | 73 | attribute 74 | end 75 | 76 | def security_group(config) 77 | ids = config.security_group.map do |name| 78 | sg = Yao::SecurityGroup.list.find {|sg| sg.name == name && Pec.get_tenant_id == sg.tenant_id } 79 | raise "security group #{name} is not found" unless sg 80 | sg.id 81 | end 82 | { security_groups: ids } 83 | end 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /lib/pec/handler/networks/allowed_address_pairs.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class Networks 3 | class AllowedAddressPairs 4 | extend Pec::Core 5 | self.kind = 'allowed_address_pairs' 6 | class << self 7 | def build(network) 8 | if network[1]['allowed_address_pairs'] 9 | pairs = network[1]['allowed_address_pairs'].map do |pair| 10 | { ip_address: pair } 11 | end 12 | { allowed_address_pairs: pairs } 13 | end 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/pec/handler/networks/ip_address.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class Networks 3 | class IpAddress 4 | extend Pec::Core 5 | self.kind = 'ip_address' 6 | class << self 7 | def build(network) 8 | ip = IP.new(network[1]['ip_address']) 9 | subnet = Yao::Subnet.list.find {|s|s.cidr == ip.network.to_s} 10 | if ip.to_s != subnet.cidr 11 | { 12 | fixed_ips: [ 13 | { subnet_id: subnet.id, ip_address: ip.to_addr} 14 | ] 15 | } 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/pec/handler/templates.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class Templates 3 | extend Pec::Core 4 | self.kind = 'templates' 5 | class << self 6 | def build(config) 7 | { user_data: load_template(config) } 8 | end 9 | 10 | def load_template(config) 11 | config.templates.inject({}) do |merge_template, template| 12 | template.to_s.concat('.yaml') unless template.to_s.match(/.*\.yaml/) 13 | Pec::Logger.notice "load template #{template}" 14 | 15 | raise "#{template} not fond!" unless FileTest.exist?("user_data/#{template}") 16 | merge_template.deep_merge!(YAML.load_file("user_data/#{template}").to_hash) 17 | end if config.templates 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/pec/handler/user_data.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class UserData 3 | extend Pec::Core 4 | autoload :Nic, "pec/handler/user_data/nic" 5 | self.kind = 'user_data' 6 | 7 | def self.build(config) 8 | user_data = config.user_data ? config.user_data.dup : {} 9 | user_data['fqdn'] = config.name if config.user_data && !config.user_data['fqdn'] 10 | { user_data: user_data } 11 | end 12 | 13 | def self.post_build(config, attribute) 14 | Pec.processor_matching(attribute, Pec::Handler::UserData) do |klass| 15 | attribute = klass.post_build(config, attribute) 16 | end 17 | attribute[:user_data] = Base64.encode64("#cloud-config\n" + attribute[:user_data].to_yaml) if attribute[:user_data] 18 | attribute 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/pec/handler/user_data/nic.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class UserData::Nic 3 | extend Pec::Core 4 | autoload :Base, "pec/handler/user_data/nic/base" 5 | autoload :Rhel, "pec/handler/user_data/nic/rhel" 6 | autoload :Ubuntu, "pec/handler/user_data/nic/ubuntu" 7 | self.kind = 'networks' 8 | 9 | class << self 10 | def post_build(config, attribute) 11 | nic = if config.os_type 12 | os = Pec::Handler::UserData::Nic.constants.find do |c| 13 | Object.const_get("Pec::Handler::UserData::Nic::#{c}").os_type.include?(config.os_type) 14 | end 15 | Object.const_get("Pec::Handler::UserData::Nic::#{os}") 16 | else 17 | Pec::Handler::UserData::Nic::Rhel 18 | end 19 | 20 | attribute.deep_merge( 21 | { 22 | user_data: { 23 | "write_files" => nic.gen_user_data(config.networks, ports(attribute)) 24 | } 25 | } 26 | ) 27 | end 28 | 29 | def ports(attribute) 30 | port_ids(attribute).map do |id| 31 | Yao::Port.get(id) 32 | end 33 | end 34 | 35 | def port_ids(attribute) 36 | attribute[:networks].map {|n|n[:port]} 37 | end 38 | 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/pec/handler/user_data/nic/base.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class UserData::Nic::Base 3 | class << self 4 | NAME = 0 5 | CONFIG = 1 6 | attr_accessor :os_type 7 | def gen_user_data(networks, ports) 8 | networks.map do |network| 9 | port = ports.find {|p|p.name == network[NAME]} 10 | path = network[CONFIG]['path'] || default_path(port) 11 | { 12 | 'content' => ifcfg_config(network, port), 13 | 'owner' => "root:root", 14 | 'path' => path, 15 | 'permissions' => "0644" 16 | } 17 | end 18 | end 19 | 20 | def safe_merge(base, network) 21 | # delete option column 22 | mask_column = Pec::Handler::Networks.constants.map {|c| Object.const_get("Pec::Handler::Networks::#{c}").kind } 23 | mask_config = network[CONFIG].reject {|k,v| mask_column.include?(k)} 24 | 25 | base.merge( 26 | mask_config 27 | ) 28 | end 29 | 30 | def default_path(port) 31 | raise "undfined method default_path" 32 | end 33 | 34 | def ifcfg_config(network, port) 35 | raise "undfined method ifcfg_config" 36 | end 37 | end 38 | self.os_type = [] 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/pec/handler/user_data/nic/rhel.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class UserData::Nic 3 | class Rhel < Base 4 | self.os_type = %w(centos rhel) 5 | class << self 6 | def ifcfg_config(network, port) 7 | base = { 8 | "name" => port.name, 9 | "device" => port.name, 10 | "type" => 'Ethernet', 11 | "onboot" => 'yes', 12 | "hwaddr" => port.mac_address 13 | } 14 | base.merge!( 15 | { 16 | "netmask" => IP.new(network[CONFIG]['ip_address']).netmask.to_s, 17 | "ipaddr" => port.fixed_ips.first['ip_address'] 18 | } 19 | ) if network[CONFIG]['bootproto'] == "static" 20 | safe_merge(base, network).map {|k,v| "#{k.upcase}=#{v}\n"}.join 21 | end 22 | 23 | def default_path(port) 24 | "/etc/sysconfig/network-scripts/ifcfg-#{port.name}" 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/pec/handler/user_data/nic/ubuntu.rb: -------------------------------------------------------------------------------- 1 | module Pec::Handler 2 | class UserData::Nic 3 | class Ubuntu < Base 4 | self.os_type = %w(ubuntu) 5 | class << self 6 | def gen_user_data(networks, ports) 7 | port_content = [ 8 | "auto lo\niface lo inet loopback" 9 | ] 10 | 11 | networks.map do |network| 12 | port = ports.find {|p|p.name == network[NAME]} 13 | port_content << ifcfg_config(network, port) 14 | end 15 | [ 16 | { 17 | 'content' => port_content.join("\n"), 18 | 'owner' => "root:root", 19 | 'path' => networks.first[CONFIG]['path'] || default_path(nil), 20 | 'permissions' => "0644" 21 | } 22 | ] 23 | end 24 | 25 | def ifcfg_config(network, port) 26 | base = { 27 | "auto" => port.name, 28 | "iface #{port.name} inet" => network[CONFIG]['bootproto'], 29 | } 30 | base.merge!( 31 | { 32 | "address" => port.fixed_ips.first['ip_address'], 33 | "netmask" => IP.new(network[CONFIG]['ip_address']).netmask.to_s, 34 | "hwaddress ether" => port.mac_address 35 | } 36 | ) if network[CONFIG]['bootproto'] == "static" 37 | safe_merge(base, network).reject {|k,v| k == "bootproto"}.map {|k,v| "#{k} #{v}"}.join("\n") 38 | end 39 | 40 | def default_path(port) 41 | "/etc/network/interfaces" 42 | end 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/pec/init.rb: -------------------------------------------------------------------------------- 1 | module Pec 2 | class Init 3 | class << self 4 | def create_template_dir 5 | dirname = "user_data" 6 | unless FileTest.exist?(dirname) 7 | FileUtils.mkdir_p(dirname) 8 | open("#{dirname}/web_server.yaml.sample","w") do |e| 9 | YAML.dump(Pec::Configure::Sample.user_data, e) 10 | end if FileTest.exist?(dirname) 11 | puts "create directry user_data".green 12 | end 13 | end 14 | 15 | def create_sample_config 16 | unless File.exist?("Pec.yaml") 17 | open("Pec.yaml","w") do |e| 18 | YAML.dump(Pec::Configure::Sample.pec_file, e) 19 | end 20 | puts "create configure file Pec.yaml".green 21 | end 22 | end 23 | 24 | def show_env_setting 25 | thor = Thor.new 26 | thor.say("please set env this paramater", :yellow) 27 | puts " export OS_AUTH_URL=http://your_keystone_server:port/v2.0" 28 | puts " export OS_USERNAME=your name" 29 | puts " export OS_PASSWORD=your password" 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/pec/logger.rb: -------------------------------------------------------------------------------- 1 | module Pec 2 | class Logger 3 | class << self 4 | def notice(m) 5 | puts m.white 6 | end 7 | 8 | def info(m) 9 | puts m.green 10 | end 11 | 12 | def warning(m) 13 | puts m.to_s.yellow 14 | end 15 | 16 | def critical(m) 17 | puts m.to_s.magenta 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/pec/port_error.rb: -------------------------------------------------------------------------------- 1 | class Pec::PortError < StandardError 2 | attr_accessor :attribute 3 | def initialize(ports) 4 | self.attribute = { 5 | networks: ports.map {|port| { uuid: '', port: port.id }} 6 | } if ports 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/pec/sample.rb: -------------------------------------------------------------------------------- 1 | module Pec 2 | class Configure 3 | class Sample 4 | class << self 5 | def pec_file 6 | { 7 | "your_sever_name" => { 8 | "tenant" => "your_tenant", 9 | "image" => "centos-7", 10 | "flavor" => "m1.small", 11 | "allowed_address_pairs" => "nova", 12 | "networks" => { 13 | "eth0" => { 14 | "bootproto" => "static", 15 | "ip_address" => "10.0.0.0/24", 16 | "allowed_address_pairs" => ["10.0.0.1"], 17 | "gateway" => "10.0.0.254", 18 | "dns1" => "10.0.0.10" 19 | }, 20 | "eth1" => { 21 | "bootproto" => "static", 22 | "ip_address" => "20.0.0.11/24", 23 | "gateway" => "20.0.0.254", 24 | "dns1" => "20.0.0.10" 25 | } 26 | }, 27 | "security_group" => [ 28 | "default", 29 | "www_from_any" 30 | ], 31 | "templates" => [ 32 | "web_server.yaml" 33 | ], 34 | "user_data" => { 35 | "hostname" => "pec", 36 | "fqdn" => "pec.pyama.com" 37 | } 38 | } 39 | } 40 | end 41 | 42 | def user_data 43 | { 44 | "hostname" => "pec", 45 | "fqdn" => "pec.pyama.com", 46 | "users" => [ 47 | { 48 | "name" => "centos", 49 | "groups" => "sudo", 50 | "shell" => "/bin/sh" 51 | } 52 | ] 53 | } 54 | end 55 | end 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/pec/version.rb: -------------------------------------------------------------------------------- 1 | module Pec 2 | VERSION = "1.0.4" 3 | end 4 | -------------------------------------------------------------------------------- /pec.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'pec/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "pec" 8 | spec.version = Pec::VERSION 9 | spec.authors = ["kazuhiko yamashita"] 10 | spec.email = ["pyama@pepabo.com"] 11 | 12 | spec.summary = %q{openstack vm booter.} 13 | spec.description = %q{openstack vm booter.} 14 | spec.homepage = "http://ten-snapon.com" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 19 | spec.require_paths = ["lib"] 20 | spec.add_dependency 'json' 21 | spec.add_dependency 'thor', '>= 0.20.0' 22 | spec.add_dependency 'yao', '>= 0.4.1' 23 | spec.add_dependency 'ruby-ip', '~> 0.9.3' 24 | spec.add_dependency 'colorator', '~> 0.1' 25 | spec.add_development_dependency "bundler" 26 | spec.add_development_dependency "rspec", ">= 3" 27 | spec.add_development_dependency "rspec-mocks", ">= 3" 28 | spec.add_development_dependency "rake" 29 | end 30 | -------------------------------------------------------------------------------- /spec/fixture/basic_config.yaml: -------------------------------------------------------------------------------- 1 | _default: &def 2 | image: centos-7.1_chef-12.3_puppet-3.7 3 | flavor: m1.small 4 | availability_zone: nova 5 | pyama-test001.test.com: 6 | <<: *def 7 | tenant: test_tenant 8 | security_group : 9 | - 1 10 | networks: 11 | eth0: 12 | allowed_address_pairs: 13 | - "10.2.0.0" 14 | bootproto: static 15 | ip_address: 1.1.1.1/24 16 | gateway: 1.1.1.254 17 | templates: 18 | - "user_data_template" 19 | user_data: 20 | hostname: pyama-test001 21 | users: 22 | - name: 1 23 | keypair: "example001" 24 | includes: 25 | - spec/fixture/include_config.yaml 26 | -------------------------------------------------------------------------------- /spec/fixture/erb_basic_config.yaml.erb: -------------------------------------------------------------------------------- 1 | _default: &def 2 | image: centos-7.1_chef-12.3_puppet-3.7 3 | flavor: m1.small 4 | availability_zone: nova 5 | <%= "pyama-test001.test.com" %>: 6 | <<: *def 7 | tenant: test_tenant 8 | security_group : 9 | - 1 10 | networks: 11 | eth0: 12 | allowed_address_pairs: 13 | - "10.2.0.0" 14 | bootproto: static 15 | ip_address: 1.1.1.1/24 16 | gateway: 1.1.1.254 17 | templates: 18 | - "user_data_template" 19 | user_data: 20 | hostname: pyama-test001 21 | users: 22 | - name: 1 23 | keypair: "example001" 24 | includes: 25 | - spec/fixture/erb_include_config.yaml.erb 26 | -------------------------------------------------------------------------------- /spec/fixture/erb_include_config.yaml.erb: -------------------------------------------------------------------------------- 1 | <%= "pyama-test002.test.com" %>: 2 | <<: *def 3 | tenant: include_test_tenant 4 | security_group : 5 | - 1 6 | networks: 7 | eth0: 8 | allowed_address_pairs: 9 | - "10.2.0.0" 10 | bootproto: static 11 | ip_address: 1.1.1.1/24 12 | gateway: 1.1.1.254 13 | templates: 14 | - "user_data_template" 15 | user_data: 16 | hostname: pyama-test001 17 | users: 18 | - name: 1 19 | keypair: "example001" 20 | -------------------------------------------------------------------------------- /spec/fixture/include_config.yaml: -------------------------------------------------------------------------------- 1 | pyama-test002.test.com: 2 | <<: *def 3 | tenant: include_test_tenant 4 | security_group : 5 | - 1 6 | networks: 7 | eth0: 8 | allowed_address_pairs: 9 | - "10.2.0.0" 10 | bootproto: static 11 | ip_address: 1.1.1.1/24 12 | gateway: 1.1.1.254 13 | templates: 14 | - "user_data_template" 15 | user_data: 16 | hostname: pyama-test001 17 | users: 18 | - name: 1 19 | keypair: "example001" 20 | -------------------------------------------------------------------------------- /spec/fixture/redhat_single_instance.yaml: -------------------------------------------------------------------------------- 1 | _default: &def 2 | image: centos-7.1_chef-12.3_puppet-3.7 3 | flavor: m1.small 4 | availability_zone: nova 5 | pyama-test001.test.com: 6 | <<: *def 7 | tenant: test_tenant 8 | security_group : 9 | - 1 10 | networks: 11 | eth0: 12 | allowed_address_pairs: 13 | - "10.2.0.0" 14 | bootproto: static 15 | ip_address: 1.1.1.1/24 16 | gateway: 1.1.1.254 17 | user_data: 18 | hostname: pyama-test001 19 | users: 20 | - name: 1 21 | keypair: "example001" 22 | -------------------------------------------------------------------------------- /spec/fixture/ubuntu_single_instance.yaml: -------------------------------------------------------------------------------- 1 | _default: &def 2 | image: ubuntu-example001 3 | flavor: m1.small 4 | availability_zone: nova 5 | pyama-test002.test.com: 6 | <<: *def 7 | tenant: test_tenant 8 | security_group : 9 | - 1 10 | networks: 11 | eth0: 12 | allowed_address_pairs: 13 | - "10.2.0.0" 14 | bootproto: static 15 | ip_address: 1.1.1.1/24 16 | gateway: 1.1.1.254 17 | user_data: 18 | hostname: pyama-test001 19 | users: 20 | - name: 1 21 | keypair: "example001" 22 | -------------------------------------------------------------------------------- /spec/fixture/user_data_template.yaml: -------------------------------------------------------------------------------- 1 | users: 2 | - name: 2 3 | -------------------------------------------------------------------------------- /spec/lib/command/config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Pec::Command::Config do 3 | subject { described_class.run([]) } 4 | 5 | before do 6 | Pec.config_reset 7 | allow(Pec).to receive(:init_yao).and_return(true) 8 | allow(Pec::Handler::Templates).to receive(:build).and_return({ user_data: YAML.load_file("spec/fixture/user_data_template.yaml") }) 9 | end 10 | 11 | context 'yaml' do 12 | before do 13 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/basic_config.yaml")) 14 | end 15 | 16 | it do 17 | expect { subject }.to output(print_yaml).to_stdout 18 | end 19 | end 20 | 21 | context 'erb' do 22 | before do 23 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/erb_basic_config.yaml.erb")) 24 | end 25 | 26 | it do 27 | expect { subject }.to output(print_yaml).to_stdout 28 | end 29 | end 30 | end 31 | 32 | def print_yaml 33 | <<-EOS 34 | --- 35 | pyama-test001.test.com: 36 | image: centos-7.1_chef-12.3_puppet-3.7 37 | flavor: m1.small 38 | availability_zone: nova 39 | tenant: test_tenant 40 | security_group: 41 | - 1 42 | networks: 43 | eth0: 44 | allowed_address_pairs: 45 | - 10.2.0.0 46 | bootproto: static 47 | ip_address: 1.1.1.1/24 48 | gateway: 1.1.1.254 49 | templates: 50 | - user_data_template 51 | user_data: 52 | hostname: pyama-test001 53 | users: 54 | - name: 1 55 | keypair: example001 56 | --- 57 | pyama-test002.test.com: 58 | image: centos-7.1_chef-12.3_puppet-3.7 59 | flavor: m1.small 60 | availability_zone: nova 61 | tenant: include_test_tenant 62 | security_group: 63 | - 1 64 | networks: 65 | eth0: 66 | allowed_address_pairs: 67 | - 10.2.0.0 68 | bootproto: static 69 | ip_address: 1.1.1.1/24 70 | gateway: 1.1.1.254 71 | templates: 72 | - user_data_template 73 | user_data: 74 | hostname: pyama-test001 75 | users: 76 | - name: 1 77 | keypair: example001 78 | EOS 79 | end 80 | -------------------------------------------------------------------------------- /spec/lib/command/destroy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Pec::Command::Destroy do 3 | before do 4 | Pec.config_reset 5 | 6 | allow(Pec).to receive(:init_yao).and_return(true) 7 | 8 | allow(Yao::Tenant).to receive(:list).and_return([ 9 | double(id: 1, name: "test_tenant"), 10 | double(id: 2, name: "include_test_tenant"), 11 | ]) 12 | 13 | allow(Yao::Port).to receive(:destroy) 14 | allow(Yao::Port).to receive(:list).and_return([ 15 | double(id: 1) 16 | ]) 17 | allow(Yao::Server).to receive(:list_detail).and_return(servers) 18 | end 19 | 20 | context 'destroy_insance' do 21 | subject { described_class.run([]) } 22 | let(:servers) { 23 | [ 24 | double(id: 1, name: "pyama-test001.test.com", status: "ACTIVE"), 25 | double(id: 2, name: "pyama-test002.test.com", status: "ACTIVE") 26 | ] 27 | } 28 | 29 | before do 30 | allow(Yao::Server).to receive(:destroy) 31 | end 32 | 33 | context 'filter' do 34 | before do 35 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/basic_config.yaml")) 36 | allow(Thor::LineEditor).to receive(:readline).and_return("y") 37 | end 38 | 39 | context 'any' do 40 | it do 41 | expect { subject }.not_to raise_error 42 | expect(Yao::Server).to have_received(:destroy).with(1) 43 | expect(Yao::Server).to have_received(:destroy).with(2) 44 | expect(Yao::Port).to have_received(:destroy).with(1).twice 45 | end 46 | end 47 | 48 | context 'unmatch' do 49 | subject { described_class.run(["unmatch"]) } 50 | it do 51 | expect { subject }.not_to raise_error 52 | expect(Yao::Server).not_to have_received(:destroy) 53 | end 54 | end 55 | 56 | context 'single' do 57 | subject { described_class.run([".*test002"]) } 58 | it do 59 | expect { subject }.not_to raise_error 60 | expect(Yao::Server).not_to have_received(:destroy).with(1) 61 | expect(Yao::Server).to have_received(:destroy).with(2).once 62 | end 63 | end 64 | end 65 | 66 | context 'force' do 67 | subject { Pec::CLI.new.invoke(:destroy, [], {force: force}) } 68 | 69 | before do 70 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/basic_config.yaml")) 71 | end 72 | 73 | context 'true' do 74 | let(:force) { true } 75 | it do 76 | expect { subject }.not_to raise_error 77 | expect(Yao::Server).to have_received(:destroy).with(1) 78 | expect(Yao::Server).to have_received(:destroy).with(2) 79 | end 80 | end 81 | 82 | context 'false' do 83 | let(:force) { false} 84 | before do 85 | allow(Thor::LineEditor).to receive(:readline).and_return("n") 86 | end 87 | 88 | it do 89 | expect { subject }.not_to raise_error 90 | expect(Yao::Server).not_to have_received(:destroy).with(1) 91 | expect(Yao::Server).not_to have_received(:destroy).with(2) 92 | end 93 | end 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /spec/lib/command/halt_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Pec::Command::Halt do 3 | before do 4 | Pec.config_reset 5 | 6 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/basic_config.yaml")) 7 | allow(Pec).to receive(:init_yao).and_return(true) 8 | allow(Yao::Tenant).to receive(:list).and_return([ 9 | double(id: 1, name: "test_tenant"), 10 | double(id: 2, name: "include_test_tenant"), 11 | ]) 12 | allow(Yao::Server).to receive(:list_detail).and_return(servers) 13 | allow(Yao::Server).to receive(:shutoff) 14 | end 15 | 16 | context 'shutoff_insance' do 17 | subject { described_class.run([]) } 18 | 19 | context 'status' do 20 | let(:servers) { 21 | [ 22 | double(id: 1, name: "pyama-test001.test.com", status: "SHUTOFF"), 23 | double(id: 2, name: "pyama-test002.test.com", status: "SHUTOFF") 24 | ] 25 | } 26 | 27 | context 'shutoff' do 28 | it do 29 | expect { subject }.not_to raise_error 30 | expect(Yao::Server).not_to have_received(:shutoff) 31 | end 32 | end 33 | end 34 | 35 | context 'filter' do 36 | let(:servers) { 37 | [ 38 | double(id: 1, name: "pyama-test001.test.com", status: "ACTIVE"), 39 | double(id: 2, name: "pyama-test002.test.com", status: "ACTIVE") 40 | ] 41 | } 42 | 43 | context 'any' do 44 | it do 45 | expect { subject }.not_to raise_error 46 | expect(Yao::Server).to have_received(:shutoff).with(1) 47 | expect(Yao::Server).to have_received(:shutoff).with(2) 48 | end 49 | end 50 | 51 | context 'unmatch' do 52 | subject { described_class.run(["unmatch"]) } 53 | it do 54 | expect { subject }.not_to raise_error 55 | expect(Yao::Server).not_to have_received(:shutoff) 56 | end 57 | end 58 | 59 | context 'single' do 60 | subject { described_class.run([".*test002"]) } 61 | it do 62 | expect { subject }.not_to raise_error 63 | expect(Yao::Server).not_to have_received(:shutoff).with(1) 64 | expect(Yao::Server).to have_received(:shutoff).with(2).once 65 | end 66 | end 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/lib/command/status_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Pec::Command::Status do 3 | before do 4 | Pec.config_reset 5 | 6 | allow(Pec).to receive(:init_yao).and_return(true) 7 | 8 | allow(Yao::Tenant).to receive(:list).and_return(tenant) 9 | 10 | allow(Yao::Server).to receive(:list_detail).and_return( 11 | [ 12 | double( 13 | id: 1, 14 | tenant_id: 1, 15 | flavor: { "id" => 1 }, 16 | name: "pyama-test001.test.com", 17 | status: "ACTIVE", 18 | availability_zone: "az1", 19 | key_name: "key1", 20 | ext_srv_attr_host: "compute1", 21 | addresses: [ 22 | [ 23 | "if", 24 | [ 25 | { "addr" => "1.1.1.1" } 26 | ] 27 | ] 28 | ] 29 | ), 30 | double( 31 | id: 2, 32 | tenant_id: 2, 33 | flavor: { "id" => 2 }, 34 | name: "pyama-test002.test.com", 35 | status: "ACTIVE", 36 | availability_zone: "az2", 37 | key_name: "key2", 38 | ext_srv_attr_host: "compute2", 39 | addresses: [ 40 | [ 41 | "if", 42 | [ 43 | { "addr" => "2.2.2.2" }, 44 | { "addr" => "3.3.3.3" } 45 | ] 46 | ] 47 | ] 48 | ) 49 | ] 50 | ) 51 | 52 | allow(Yao::Image).to receive(:list).and_return([ 53 | double(id: 1, name: "centos-7.1_chef-12.3_puppet-3.7"), 54 | double(id: 2, name: "ubuntu-example001") 55 | ]) 56 | 57 | allow(Yao::Flavor).to receive(:list).and_return( 58 | flavor 59 | ) 60 | 61 | allow(Yao::Port).to receive(:get).and_return( 62 | double(id: 1, name: "eth0", mac_address: '00:00:00:00:00:00', fixed_ips: [ { 'ip_address' => "10.10.10.10" } ]) 63 | ) 64 | 65 | end 66 | 67 | context 'show_instance' do 68 | subject { described_class.run([]) } 69 | 70 | let(:tenant) {[ 71 | double(id: 1, name: "test_tenant"), 72 | double(id: 2, name: "include_test_tenant"), 73 | ]} 74 | 75 | let(:flavor) {[ 76 | double(id: 1, name: "m1.small"), 77 | double(id: 2, name: "m2.small") 78 | ]} 79 | 80 | 81 | before do 82 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/basic_config.yaml")) 83 | allow(Pec::Handler::Templates).to receive(:build).and_return({ user_data: YAML.load_file("spec/fixture/user_data_template.yaml") }) 84 | end 85 | 86 | context 'filter' do 87 | context 'any' do 88 | it do 89 | expect { subject }.to output(print_any).to_stdout 90 | end 91 | end 92 | 93 | context 'unmatch' do 94 | subject { described_class.run(["unmatch"]) } 95 | it do 96 | expect { subject }.to output(print_unmatch).to_stdout 97 | end 98 | end 99 | 100 | context 'single' do 101 | subject { described_class.run([".*test002"]) } 102 | it do 103 | expect { subject }.to output(print_single).to_stdout 104 | end 105 | end 106 | end 107 | 108 | context 'delete_resource' do 109 | context 'flavor' do 110 | let(:flavor) {[ 111 | double(id: 1, name: "m1.small") 112 | ]} 113 | it do 114 | expect { subject }.to output(print_delete_flavor).to_stdout 115 | end 116 | end 117 | end 118 | end 119 | end 120 | 121 | def print_any 122 | <<-EOS 123 | \e[33mCurrent machine status:\e[0m 124 | pyama-test001.test.com ACTIVE test_tenant m1.small az1 key1 compute1 1.1.1.1 125 | pyama-test002.test.com ACTIVE include_test_tenant m2.small az2 key2 compute2 2.2.2.2,3.3.3.3 126 | EOS 127 | end 128 | 129 | def print_unmatch 130 | <<-EOS 131 | \e[33mCurrent machine status:\e[0m 132 | EOS 133 | end 134 | 135 | def print_single 136 | <<-EOS 137 | \e[33mCurrent machine status:\e[0m 138 | pyama-test002.test.com ACTIVE include_test_tenant m2.small az2 key2 compute2 2.2.2.2,3.3.3.3 139 | EOS 140 | end 141 | 142 | def print_delete_flavor 143 | <<-EOS 144 | \e[33mCurrent machine status:\e[0m 145 | pyama-test001.test.com ACTIVE test_tenant m1.small az1 key1 compute1 1.1.1.1 146 | pyama-test002.test.com ACTIVE include_test_tenant m1.small az2 key2 compute2 2.2.2.2,3.3.3.3 147 | \e[33mpyama-test002.test.com:flavor is unmatch id. may be id has changed\e[0m 148 | EOS 149 | end 150 | -------------------------------------------------------------------------------- /spec/lib/command/up_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Pec::Command::Up do 3 | before do 4 | Pec.config_reset 5 | 6 | allow(Pec).to receive(:init_yao).and_return(true) 7 | 8 | allow(Yao).to receive(:current_tenant_id).and_return(1) 9 | 10 | allow(Yao::Tenant).to receive(:list).and_return([ 11 | double(id: 1, name: "test_tenant"), 12 | double(id: 2, name: "include_test_tenant"), 13 | ]) 14 | 15 | allow(Yao::Server).to receive(:list_detail).and_return(servers) 16 | 17 | allow(Yao::Image).to receive(:list).and_return([ 18 | double(id: 1, name: "centos-7.1_chef-12.3_puppet-3.7"), 19 | double(id: 2, name: "ubuntu-example001") 20 | ]) 21 | 22 | allow(Yao::Flavor).to receive(:list).and_return([ 23 | double(id: 1, name: "m1.small") 24 | ]) 25 | 26 | allow(Yao::SecurityGroup).to receive(:list).and_return([ 27 | double(id: 1, tenant_id: 1, name: 1), 28 | double(id: 1, tenant_id: 2, name: 1) 29 | ]) 30 | 31 | allow(Yao::Subnet).to receive(:list).and_return([ 32 | double(id: 1, network_id: 1, cidr: "1.1.1.0/24") 33 | ]) 34 | 35 | allow(Yao::Port).to receive(:create).and_return( 36 | double(id: 1, name: "eth0", mac_address: '00:00:00:00:00:00', fixed_ips: [ { 'ip_address' => "10.10.10.10" } ]) 37 | ) 38 | 39 | allow(Yao::Port).to receive(:get).and_return( 40 | double(id: 1, name: "eth0", mac_address: '00:00:00:00:00:00', fixed_ips: [ { 'ip_address' => "10.10.10.10" } ]) 41 | ) 42 | 43 | allow(Yao::Keypair).to receive(:list).and_return([ 44 | double(id: 1, name: "example001") 45 | ]) 46 | end 47 | 48 | context 'create_instance' do 49 | subject { described_class.run([]) } 50 | let(:servers) { [] } 51 | 52 | before do 53 | allow(Yao::Server).to receive(:create) 54 | end 55 | 56 | context 'rhel' do 57 | before do 58 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/redhat_single_instance.yaml")) 59 | end 60 | 61 | it do 62 | expect { subject }.not_to raise_error 63 | expect(Yao::Server).to have_received(:create).with(create_rhel) 64 | end 65 | end 66 | 67 | context 'ubuntu' do 68 | before do 69 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/ubuntu_single_instance.yaml")) 70 | end 71 | 72 | it do 73 | expect { subject }.not_to raise_error 74 | expect(Yao::Server).to have_received(:create).with(create_ubuntu) 75 | end 76 | end 77 | 78 | context 'filter' do 79 | before do 80 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/basic_config.yaml")) 81 | allow(Pec::Handler::Templates).to receive(:build).and_return({ user_data: YAML.load_file("spec/fixture/user_data_template.yaml") }) 82 | end 83 | context 'any' do 84 | it do 85 | expect { subject }.not_to raise_error 86 | expect(Yao::Server).to have_received(:create).with(create_basic_1) 87 | expect(Yao::Server).to have_received(:create).with(create_basic_2) 88 | end 89 | end 90 | 91 | context 'unmatch' do 92 | subject { described_class.run(["unmatch"]) } 93 | it do 94 | expect { subject }.not_to raise_error 95 | expect(Yao::Server).not_to have_received(:create) 96 | end 97 | end 98 | 99 | context 'single' do 100 | subject { described_class.run([".*test002"]) } 101 | it do 102 | expect { subject }.not_to raise_error 103 | expect(Yao::Server).not_to have_received(:create).with(create_basic_1) 104 | expect(Yao::Server).to have_received(:create).with(create_basic_2).once 105 | end 106 | end 107 | end 108 | 109 | context 'recovery' do 110 | before do 111 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/redhat_single_instance.yaml")) 112 | allow(Yao::Port).to receive(:destroy) 113 | allow(Yao::Server).to receive(:create).and_raise("create error") 114 | end 115 | 116 | it do 117 | expect { subject }.not_to raise_error 118 | expect(Yao::Port).to have_received(:destroy).with(1) 119 | end 120 | end 121 | end 122 | 123 | context 'not_created' do 124 | subject { described_class.run([]) } 125 | before do 126 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/redhat_single_instance.yaml")) 127 | allow(Yao::Server).to receive(:create) 128 | allow(Yao::Server).to receive(:start) 129 | end 130 | 131 | context 'start' do 132 | let(:servers) { [double(id: 1, name: "pyama-test001.test.com", status: "SHUTOFF")] } 133 | 134 | it do 135 | expect { subject }.not_to raise_error 136 | expect(Yao::Server).not_to have_received(:create) 137 | expect(Yao::Server).to have_received(:start).with(1).once 138 | end 139 | end 140 | 141 | context 'active' do 142 | let(:servers) { [double(id: 1, name: "pyama-test001.test.com", status: "ACTIVE")] } 143 | 144 | it do 145 | expect { subject }.not_to raise_error 146 | expect(Yao::Server).not_to have_received(:create) 147 | expect(Yao::Server).not_to have_received(:start) 148 | end 149 | end 150 | end 151 | end 152 | 153 | def create_rhel 154 | { 155 | :name => "pyama-test001.test.com", 156 | :imageRef => 1, 157 | :flavorRef => 1, 158 | :availability_zone => "nova", 159 | :networks => [{:uuid => '', :port => 1}], 160 | :user_data => "I2Nsb3VkLWNvbmZpZwotLS0KaG9zdG5hbWU6IHB5YW1hLXRlc3QwMDEKdXNl\ncnM6Ci0gbmFtZTogMQpmcWRuOiBweWFtYS10ZXN0MDAxLnRlc3QuY29tCndy\naXRlX2ZpbGVzOgotIGNvbnRlbnQ6IHwKICAgIE5BTUU9ZXRoMAogICAgREVW\nSUNFPWV0aDAKICAgIFRZUEU9RXRoZXJuZXQKICAgIE9OQk9PVD15ZXMKICAg\nIEhXQUREUj0wMDowMDowMDowMDowMDowMAogICAgTkVUTUFTSz0yNTUuMjU1\nLjI1NS4wCiAgICBJUEFERFI9MTAuMTAuMTAuMTAKICAgIEJPT1RQUk9UTz1z\ndGF0aWMKICAgIEdBVEVXQVk9MS4xLjEuMjU0CiAgb3duZXI6IHJvb3Q6cm9v\ndAogIHBhdGg6ICIvZXRjL3N5c2NvbmZpZy9uZXR3b3JrLXNjcmlwdHMvaWZj\nZmctZXRoMCIKICBwZXJtaXNzaW9uczogJzA2NDQnCg==\n", 161 | :key_name => "example001" 162 | } 163 | end 164 | 165 | def create_ubuntu 166 | { 167 | :name => "pyama-test002.test.com", 168 | :imageRef => 2, 169 | :flavorRef => 1, 170 | :availability_zone => "nova", 171 | :networks => [{:uuid => '', :port => 1}], 172 | :user_data => "I2Nsb3VkLWNvbmZpZwotLS0KaG9zdG5hbWU6IHB5YW1hLXRlc3QwMDEKdXNl\ncnM6Ci0gbmFtZTogMQpmcWRuOiBweWFtYS10ZXN0MDAyLnRlc3QuY29tCndy\naXRlX2ZpbGVzOgotIGNvbnRlbnQ6IHwKICAgIE5BTUU9ZXRoMAogICAgREVW\nSUNFPWV0aDAKICAgIFRZUEU9RXRoZXJuZXQKICAgIE9OQk9PVD15ZXMKICAg\nIEhXQUREUj0wMDowMDowMDowMDowMDowMAogICAgTkVUTUFTSz0yNTUuMjU1\nLjI1NS4wCiAgICBJUEFERFI9MTAuMTAuMTAuMTAKICAgIEJPT1RQUk9UTz1z\ndGF0aWMKICAgIEdBVEVXQVk9MS4xLjEuMjU0CiAgb3duZXI6IHJvb3Q6cm9v\ndAogIHBhdGg6ICIvZXRjL3N5c2NvbmZpZy9uZXR3b3JrLXNjcmlwdHMvaWZj\nZmctZXRoMCIKICBwZXJtaXNzaW9uczogJzA2NDQnCg==\n", :key_name => "example001" 173 | } 174 | end 175 | 176 | def create_basic_1 177 | { 178 | :name => "pyama-test001.test.com", 179 | :imageRef => 1, 180 | :flavorRef => 1, 181 | :availability_zone => "nova", 182 | :networks => [{:uuid => '', :port => 1}], 183 | :user_data => "I2Nsb3VkLWNvbmZpZwotLS0KdXNlcnM6Ci0gbmFtZTogMgotIG5hbWU6IDEK\naG9zdG5hbWU6IHB5YW1hLXRlc3QwMDEKZnFkbjogcHlhbWEtdGVzdDAwMS50\nZXN0LmNvbQp3cml0ZV9maWxlczoKLSBjb250ZW50OiB8CiAgICBOQU1FPWV0\naDAKICAgIERFVklDRT1ldGgwCiAgICBUWVBFPUV0aGVybmV0CiAgICBPTkJP\nT1Q9eWVzCiAgICBIV0FERFI9MDA6MDA6MDA6MDA6MDA6MDAKICAgIE5FVE1B\nU0s9MjU1LjI1NS4yNTUuMAogICAgSVBBRERSPTEwLjEwLjEwLjEwCiAgICBC\nT09UUFJPVE89c3RhdGljCiAgICBHQVRFV0FZPTEuMS4xLjI1NAogIG93bmVy\nOiByb290OnJvb3QKICBwYXRoOiAiL2V0Yy9zeXNjb25maWcvbmV0d29yay1z\nY3JpcHRzL2lmY2ZnLWV0aDAiCiAgcGVybWlzc2lvbnM6ICcwNjQ0Jwo=\n", 184 | :key_name => "example001" 185 | } 186 | end 187 | 188 | def create_basic_2 189 | { 190 | :name => "pyama-test002.test.com", 191 | :imageRef => 1, 192 | :flavorRef => 1, 193 | :availability_zone => "nova", 194 | :networks => [{:uuid => '', :port => 1}], 195 | :user_data => "I2Nsb3VkLWNvbmZpZwotLS0KdXNlcnM6Ci0gbmFtZTogMgotIG5hbWU6IDEK\naG9zdG5hbWU6IHB5YW1hLXRlc3QwMDEKZnFkbjogcHlhbWEtdGVzdDAwMi50\nZXN0LmNvbQp3cml0ZV9maWxlczoKLSBjb250ZW50OiB8CiAgICBOQU1FPWV0\naDAKICAgIERFVklDRT1ldGgwCiAgICBUWVBFPUV0aGVybmV0CiAgICBPTkJP\nT1Q9eWVzCiAgICBIV0FERFI9MDA6MDA6MDA6MDA6MDA6MDAKICAgIE5FVE1B\nU0s9MjU1LjI1NS4yNTUuMAogICAgSVBBRERSPTEwLjEwLjEwLjEwCiAgICBC\nT09UUFJPVE89c3RhdGljCiAgICBHQVRFV0FZPTEuMS4xLjI1NAogIG93bmVy\nOiByb290OnJvb3QKICBwYXRoOiAiL2V0Yy9zeXNjb25maWcvbmV0d29yay1z\nY3JpcHRzL2lmY2ZnLWV0aDAiCiAgcGVybWlzc2lvbnM6ICcwNjQ0Jwo=\n", 196 | :key_name => "example001" 197 | } 198 | end 199 | -------------------------------------------------------------------------------- /spec/lib/configure_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Pec do 3 | before do 4 | Pec.config_reset 5 | end 6 | 7 | shared_examples_for 'value_check' do 8 | before do 9 | Pec.load_config(file_name) 10 | end 11 | 12 | it do 13 | expect(Pec.configure.first.name).to eq("pyama-test001.test.com") 14 | expect(Pec.configure.first.tenant).to eq("test_tenant") 15 | expect(Pec.configure.first.availability_zone).to eq("nova") 16 | expect(Pec.configure.last.name).to eq("pyama-test002.test.com") 17 | expect(Pec.configure.last.tenant).to eq("include_test_tenant") 18 | end 19 | end 20 | context 'yaml' do 21 | let(:file_name) {"spec/fixture/basic_config.yaml"} 22 | it_behaves_like 'value_check' 23 | end 24 | 25 | context 'erb' do 26 | let(:file_name) {"spec/fixture/erb_basic_config.yaml.erb"} 27 | it_behaves_like 'value_check' 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/lib/handler/keypair_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'ostruct' 3 | 4 | describe Pec::Handler::Keypair do 5 | before do 6 | Pec.load_config("spec/fixture/basic_config.yaml") 7 | 8 | allow(Yao::Keypair).to receive(:list).and_return(os_keypairs) 9 | end 10 | 11 | subject { 12 | described_class.build(Pec.configure.first) 13 | } 14 | 15 | context "Valid keypair name" do 16 | let(:os_keypairs) do 17 | [ 18 | double( 19 | id: 1, 20 | name: "example001" 21 | ) 22 | ] 23 | end 24 | 25 | it { 26 | expect(subject).to eq( 27 | {key_name: "example001"} 28 | ) 29 | } 30 | end 31 | 32 | context "invalid keypair name" do 33 | let(:os_keypairs) do 34 | [ 35 | double( 36 | id: 1, 37 | name: "invalid-example001" 38 | ) 39 | ] 40 | end 41 | 42 | it { 43 | expect{ subject }.to raise_error(Pec::ConfigError) 44 | } 45 | end 46 | 47 | context "no keypair" do 48 | let(:os_keypairs) do 49 | [ 50 | double( 51 | id: 1, 52 | name: "example001" 53 | ) 54 | ] 55 | end 56 | 57 | it { 58 | allow(Pec.configure).to receive(:first).and_return(double(keypair: nil)) 59 | expect(subject).to eq({}) 60 | } 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/lib/handler/networks_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'ostruct' 3 | describe Pec::Handler::Networks do 4 | before do 5 | Pec.load_config("spec/fixture/basic_config.yaml") 6 | allow(Yao::Port).to receive(:create).and_return( 7 | double( 8 | id: 1, 9 | name: "eth0", 10 | mac_address: '00:00:00:00:00:00', 11 | fixed_ips: [ 12 | { 13 | 'ip_address' => "10.10.10.10" 14 | } 15 | ] 16 | ) 17 | ) 18 | 19 | allow(Yao).to receive(:current_tenant_id).and_return(1) 20 | allow(Yao::SecurityGroup).to receive(:list).and_return([double(id: 1, tenant_id: 1, name: 1)]) 21 | allow(Yao::Tenant).to receive(:list).and_return([double(id: 1, name: "test_tenant")]) 22 | allow(Yao::Subnet).to receive(:list).and_return([double(id: 1, network_id: 1, cidr: "1.1.1.0/24") ]) 23 | end 24 | 25 | context 'build' do 26 | subject { 27 | described_class.build(Pec.configure.first) 28 | } 29 | 30 | it do 31 | expect(subject).to eq({networks: [{uuid: '', port: 1}]}) 32 | end 33 | end 34 | 35 | context 'port attribute' do 36 | before do 37 | allow(described_class).to receive(:security_group).and_return({security_groups: [1]}) 38 | end 39 | 40 | context 'static' do 41 | before do 42 | allow(Yao::Subnet).to receive(:list).and_return([double(id: 1, network_id: 1, cidr: "1.1.1.0/24")]) 43 | end 44 | 45 | subject { 46 | described_class.gen_port_attribute( 47 | Pec.configure.first, 48 | Pec.configure.first.networks.first 49 | ) 50 | } 51 | 52 | it do 53 | expect(subject).to eq({ 54 | :name=>"eth0", 55 | :network_id=>1, 56 | :security_groups=> [1], 57 | :allowed_address_pairs=>[{ 58 | :ip_address => "10.2.0.0" 59 | }], 60 | :fixed_ips => [{ 61 | :subnet_id => 1, 62 | :ip_address => "1.1.1.1" 63 | }] 64 | }) 65 | end 66 | end 67 | 68 | context 'any_address' do 69 | before do 70 | Pec.configure.first.networks['eth0']['ip_address'] = '1.1.1.0/24' 71 | end 72 | subject { 73 | described_class.gen_port_attribute( 74 | Pec.configure.first, 75 | Pec.configure.first.networks.first 76 | ) 77 | } 78 | it do 79 | expect(subject).to eq( 80 | { 81 | name: "eth0", 82 | network_id: 1, 83 | security_groups: [1], 84 | allowed_address_pairs: [{ 85 | ip_address: "10.2.0.0" 86 | }] 87 | } 88 | ) 89 | end 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /spec/lib/handler/templates_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Pec::Handler::Templates do 3 | before do 4 | Pec.config_reset 5 | allow(Pec).to receive(:load_config).and_return(Pec.load_config("spec/fixture/basic_config.yaml")) 6 | allow(FileTest).to receive(:exist?).and_return(true) 7 | allow(YAML).to receive(:load_file).and_return(YAML.load_file("spec/fixture/user_data_template.yaml")) 8 | end 9 | 10 | subject { 11 | described_class.build(Pec.configure.first) 12 | } 13 | 14 | it 'value_check' do 15 | expect(subject).to eq( 16 | { 17 | :user_data => 18 | { 19 | "users"=> [ 20 | { 21 | "name" => 2 22 | } 23 | ] 24 | } 25 | } 26 | ) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/lib/handler/user_data_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'support/nic_helper' 3 | describe Pec::Handler::UserData do 4 | before do 5 | Pec.load_config("spec/fixture/basic_config.yaml") 6 | allow(FileTest).to receive(:exist?).and_return(true) 7 | allow(YAML).to receive(:load_file).and_return(YAML.load_file("spec/fixture/user_data_template.yaml")) 8 | end 9 | 10 | subject { 11 | described_class.build(Pec.configure.first) 12 | } 13 | 14 | it 'value_check' do 15 | expect(subject).to eq( 16 | { 17 | :user_data => 18 | { 19 | "hostname" => "pyama-test001", 20 | "users"=> [ 21 | { 22 | "name" => 1 23 | } 24 | ], 25 | "fqdn" => "pyama-test001.test.com" 26 | } 27 | } 28 | ) 29 | end 30 | 31 | describe Pec::Handler::UserData::Nic::Ubuntu do 32 | 33 | subject { described_class.gen_user_data(networks, ports) } 34 | it { 35 | expect(subject).to eq( 36 | [ 37 | { 38 | "content" => "auto lo\niface lo inet loopback\nauto eth0\niface eth0 inet static\naddress 10.10.10.10\nnetmask 255.255.255.0\nhwaddress ether 00:00:00:00:00:00\ndns-nameservers 8.8.8.8\ngateway 1.1.1.1\nauto eth1\niface eth1 inet static\naddress 20.20.20.20\nnetmask 255.255.255.0\nhwaddress ether 00:00:00:00:00:00\ndns-nameservers 8.8.8.8\ngateway 2.2.2.2", 39 | "owner" => "root:root", 40 | "path" => "/etc/network/interfaces", 41 | "permissions" => "0644" 42 | } 43 | ] 44 | ) 45 | } 46 | end 47 | 48 | describe Pec::Handler::UserData::Nic::Rhel do 49 | subject { described_class.gen_user_data(networks, ports) } 50 | it { 51 | expect(subject).to eq( 52 | [ 53 | { 54 | "content" => "NAME=eth0\nDEVICE=eth0\nTYPE=Ethernet\nONBOOT=yes\nHWADDR=00:00:00:00:00:00\nNETMASK=255.255.255.0\nIPADDR=10.10.10.10\nBOOTPROTO=static\nDNS-NAMESERVERS=8.8.8.8\nGATEWAY=1.1.1.1\n", 55 | "owner" => "root:root", 56 | "path" => "/etc/sysconfig/network-scripts/ifcfg-eth0", 57 | "permissions" => "0644" 58 | }, 59 | { 60 | "content" => "NAME=eth1\nDEVICE=eth1\nTYPE=Ethernet\nONBOOT=yes\nHWADDR=00:00:00:00:00:00\nNETMASK=255.255.255.0\nIPADDR=20.20.20.20\nBOOTPROTO=static\nDNS-NAMESERVERS=8.8.8.8\nGATEWAY=2.2.2.2\n", 61 | "owner" => "root:root", 62 | "path" => "/etc/sysconfig/network-scripts/ifcfg-eth1", 63 | "permissions" => "0644" 64 | } 65 | ] 66 | ) 67 | } 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'pec' 3 | require 'rspec' 4 | require 'simplecov' 5 | SimpleCov.start 6 | 7 | Dir["./support/**/*.rb"].each do |f| 8 | require f 9 | end 10 | 11 | RSpec.configure do |config| 12 | end 13 | 14 | -------------------------------------------------------------------------------- /spec/support/nic_helper.rb: -------------------------------------------------------------------------------- 1 | def ports 2 | [ 3 | double( 4 | id: 1, 5 | name: "eth0", 6 | mac_address: '00:00:00:00:00:00', 7 | fixed_ips: [ 8 | { 9 | 'ip_address' => "10.10.10.10" 10 | } 11 | ] 12 | ), 13 | double( 14 | id: 1, 15 | name: "eth1", 16 | mac_address: '00:00:00:00:00:00', 17 | fixed_ips: [ 18 | { 19 | 'ip_address' => "20.20.20.20" 20 | } 21 | ] 22 | ) 23 | ] 24 | end 25 | 26 | def networks 27 | [ 28 | [ 29 | "eth0", 30 | { 31 | "bootproto" => "static", 32 | "ip_address" => "10.10.10.10/24", 33 | "dns-nameservers" => "8.8.8.8", 34 | "gateway" => "1.1.1.1" 35 | } 36 | ], 37 | [ 38 | "eth1", 39 | { 40 | "bootproto" => "static", 41 | "ip_address" => "20.20.20.20/24", 42 | "dns-nameservers" => "8.8.8.8", 43 | "gateway" => "2.2.2.2" 44 | } 45 | ] 46 | ] 47 | end 48 | --------------------------------------------------------------------------------