knife-topo 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/lib/chef/knife/topo/version.rb +1 -1
- data/lib/chef/knife/topo_bootstrap.rb +32 -34
- data/lib/chef/knife/topo_cookbook_create.rb +1 -1
- data/lib/chef/knife/topo_create.rb +53 -13
- data/lib/chef/knife/topo_delete.rb +2 -2
- data/lib/chef/knife/topo_list.rb +6 -2
- data/lib/chef/knife/topology_helper.rb +52 -1
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a5982dbdd98f486734b60e5f8f7d6db46c18daf2
         | 
| 4 | 
            +
              data.tar.gz: 8ba53f9163e5c9883f7098319c9a3955d9c24d14
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1a273459319db01f84a3bdfd1507ef5a1c9f201829087d439473fc38aeb2c68c1eec8c4699971b551081bb4f1ce2e6d85d1e7630eae07ba945326d073d833613
         | 
| 7 | 
            +
              data.tar.gz: 644dd730a1e628f4adc3cf2d6f7b3e1f6dcacbb1f1e5e762df157aed9484a14aa0f998d583e760aa9337324ddca0ddc07d18bead4173488d59ed97a73cda9abb
         | 
    
        data/README.md
    CHANGED
    
    | @@ -338,7 +338,7 @@ The following will create the 'test1' topology, and bootstrap it. | |
| 338 338 | 
             
            The following will create the 'test1' topology but will not bootstrap it 
         | 
| 339 339 | 
             
            or upload topology cookbooks.
         | 
| 340 340 |  | 
| 341 | 
            -
            $ knife topo create test1 --disable-upload
         | 
| 341 | 
            +
            	$ knife topo create test1 --disable-upload
         | 
| 342 342 |  | 
| 343 343 | 
             
            ## knife topo delete <a name="delete"></a>
         | 
| 344 344 |  | 
| @@ -378,17 +378,17 @@ Option        | Description | |
| 378 378 | 
             
            The following will export the data for nodes n1 and n2 as part of a 
         | 
| 379 379 | 
             
            topology called 'my_topo':
         | 
| 380 380 |  | 
| 381 | 
            -
            	$ knife topo export n1 n2 --topo | 
| 381 | 
            +
            	$ knife topo export n1 n2 --topo my_topo > new_topo.json
         | 
| 382 382 |  | 
| 383 383 |  | 
| 384 | 
            -
            The following will export all topologies to a file called 'all_topos.json'.
         | 
| 384 | 
            +
            The following will export all existing topologies to a file called 'all_topos.json'.
         | 
| 385 385 |  | 
| 386 386 | 
             
            	$ knife topo export --all > all_topos.json
         | 
| 387 387 |  | 
| 388 388 | 
             
            The following will create an outline for a new topology called  
         | 
| 389 389 | 
             
            'christine_test', or export the current details if it already exists:
         | 
| 390 390 |  | 
| 391 | 
            -
            	$ knife topo export --topo | 
| 391 | 
            +
            	$ knife topo export --topo christine_test > christine_test.json
         | 
| 392 392 |  | 
| 393 393 |  | 
| 394 394 | 
             
            ## knife topo import <a name="import"></a>
         | 
| @@ -34,6 +34,11 @@ class Chef | |
| 34 34 | 
             
                  :short => '-D DATA_BAG',
         | 
| 35 35 | 
             
                  :long => "--data-bag DATA_BAG",
         | 
| 36 36 | 
             
                  :description => "The data bag the topologies are stored in"
         | 
| 37 | 
            +
                  
         | 
| 38 | 
            +
                  option :overwrite,
         | 
| 39 | 
            +
                  :long => "--overwrite",
         | 
| 40 | 
            +
                  :description => "Whether to overwrite existing nodes",
         | 
| 41 | 
            +
                  :boolean => true
         | 
| 37 42 |  | 
| 38 43 | 
             
                  # Make the base bootstrap options available on topo bootstrap
         | 
| 39 44 | 
             
                  self.options = (Chef::Knife::Bootstrap.options).merge(self.options)
         | 
| @@ -65,50 +70,43 @@ class Chef | |
| 65 70 |  | 
| 66 71 | 
             
                    # load and bootstrap each node that has a ssh_host
         | 
| 67 72 | 
             
                    nodes = merge_topo_properties(topo['nodes'], topo)
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                     | 
| 70 | 
            -
                     | 
| 73 | 
            +
                      
         | 
| 74 | 
            +
                    bootstrapped = []
         | 
| 75 | 
            +
                    skipped = []
         | 
| 76 | 
            +
                    existed = []
         | 
| 77 | 
            +
                    failed = [] 
         | 
| 78 | 
            +
                      
         | 
| 71 79 | 
             
                    if nodes.length > 0
         | 
| 72 80 | 
             
                      nodes.each do |node_data|
         | 
| 73 | 
            -
                         | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 81 | 
            +
                        node_name = node_data['name']
         | 
| 82 | 
            +
                        exists = resource_exists?("nodes/#{node_name}") 
         | 
| 83 | 
            +
                        if(node_data['ssh_host'] && (config[:overwrite] || !exists))
         | 
| 84 | 
            +
                          if run_bootstrap(node_data, @bootstrap_args, exists)
         | 
| 85 | 
            +
                            bootstrapped << node_name
         | 
| 86 | 
            +
                          else
         | 
| 87 | 
            +
                            failed << node_name
         | 
| 88 | 
            +
                          end
         | 
| 76 89 | 
             
                        else
         | 
| 77 | 
            -
                           | 
| 78 | 
            -
             | 
| 90 | 
            +
                          if(exists)
         | 
| 91 | 
            +
                            existed << node_name
         | 
| 92 | 
            +
                          else
         | 
| 93 | 
            +
                            skipped << node_name
         | 
| 94 | 
            +
                          end
         | 
| 79 95 | 
             
                        end
         | 
| 80 | 
            -
             | 
| 81 96 | 
             
                      end
         | 
| 82 | 
            -
                      ui.info | 
| 83 | 
            -
                      ui. | 
| 97 | 
            +
                      ui.info("Bootstrapped #{bootstrapped.length} nodes [ #{bootstrapped.join(', ')} ]")
         | 
| 98 | 
            +
                      ui.info("Skipped #{skipped.length} nodes [ #{skipped.join(', ')} ] because they had no ssh_host information") if skipped.length > 0
         | 
| 99 | 
            +
                      if existed.length > 0
         | 
| 100 | 
            +
                        ui.info("Skipped #{existed.length} nodes [ #{existed.join(', ')} ] because they already exist. " +
         | 
| 101 | 
            +
                          "Specify --overwrite to re-bootstrap existing nodes. " +
         | 
| 102 | 
            +
                          "If you are using Chef Vault, you may need to use --bootstrap-vault options in this case.")
         | 
| 103 | 
            +
                      end
         | 
| 104 | 
            +
                      ui.warn("#{failed.length} nodes [ #{failed.join(', ')} ] failed to bootstrap due to errors") if failed.length > 0
         | 
| 84 105 | 
             
                    else
         | 
| 85 106 | 
             
                      ui.info "No nodes found for topology #{display_name(topo)}"
         | 
| 86 107 | 
             
                    end
         | 
| 87 108 | 
             
                  end
         | 
| 88 109 |  | 
| 89 | 
            -
                  # Setup the bootstrap args and run the bootstrap command
         | 
| 90 | 
            -
                  def run_bootstrap(node_data)
         | 
| 91 | 
            -
                    node_name = node_data['name']
         | 
| 92 | 
            -
                      
         | 
| 93 | 
            -
                    args = @bootstrap_args
         | 
| 94 | 
            -
                    args += ['-N', node_name] if(node_name)
         | 
| 95 | 
            -
                    args += ['-E', node_data['chef_environment']] if(node_data['chef_environment'])
         | 
| 96 | 
            -
                    args[1] = node_data['ssh_host']
         | 
| 97 | 
            -
                    args += [ '--ssh-port', node_data['ssh_port']] if node_data['ssh_port']
         | 
| 98 | 
            -
                    args += [ '--run-list' , node_data['run_list'].join(',')] if node_data['run_list']
         | 
| 99 | 
            -
                    args += [ '--json-attributes' , node_data['normal'].to_json] if node_data['normal']
         | 
| 100 | 
            -
             | 
| 101 | 
            -
                    ui.info "Bootstrapping node #{node_name}"
         | 
| 102 | 
            -
                    begin
         | 
| 103 | 
            -
                      run_cmd(Chef::Knife::Bootstrap, args)
         | 
| 104 | 
            -
                    rescue Exception => e
         | 
| 105 | 
            -
                      raise if Chef::Config[:verbosity] == 2
         | 
| 106 | 
            -
                      @failed << node_name
         | 
| 107 | 
            -
                      ui.warn "bootstrap of node #{node_name} exited with error"
         | 
| 108 | 
            -
                      humanize_exception(e)
         | 
| 109 | 
            -
                    end
         | 
| 110 | 
            -
                  end
         | 
| 111 | 
            -
             | 
| 112 110 | 
             
                  include Chef::Knife::TopologyHelper
         | 
| 113 111 |  | 
| 114 112 | 
             
                end
         | 
| @@ -151,7 +151,7 @@ class Chef | |
| 151 151 |  | 
| 152 152 | 
             
                      # Print out qualified attributes
         | 
| 153 153 | 
             
                      def print_qualified_attr(file, qualifier_hash)
         | 
| 154 | 
            -
                        file.puts "if node['topo']['#{qualifier_hash['qualifier']}'] == \"#{qualifier_hash['value']}\""
         | 
| 154 | 
            +
                        file.puts "if node['topo'] && node['topo']['#{qualifier_hash['qualifier']}'] == \"#{qualifier_hash['value']}\""
         | 
| 155 155 | 
             
                        print_priority_attrs(file, qualifier_hash, 2)
         | 
| 156 156 | 
             
                        file.puts "end"
         | 
| 157 157 | 
             
                      end
         | 
| @@ -27,7 +27,7 @@ class Chef | |
| 27 27 |  | 
| 28 28 | 
             
                  deps do
         | 
| 29 29 | 
             
                    Chef::Knife::TopoCookbookUpload.load_deps
         | 
| 30 | 
            -
                    Chef::Knife:: | 
| 30 | 
            +
                    Chef::Knife::Bootstrap.load_deps
         | 
| 31 31 | 
             
                  end
         | 
| 32 32 |  | 
| 33 33 | 
             
                  banner "knife topo create TOPOLOGY (options)"
         | 
| @@ -46,19 +46,24 @@ class Chef | |
| 46 46 | 
             
                  :long => "--disable-upload",
         | 
| 47 47 | 
             
                  :description => "Do not upload topo cookbooks",
         | 
| 48 48 | 
             
                  :boolean => true
         | 
| 49 | 
            +
                  
         | 
| 50 | 
            +
                  option :overwrite,
         | 
| 51 | 
            +
                  :long => "--overwrite",
         | 
| 52 | 
            +
                  :description => "Whether to overwrite existing nodes",
         | 
| 53 | 
            +
                  :boolean => true
         | 
| 49 54 |  | 
| 50 55 | 
             
                  # Make called command options available
         | 
| 51 56 | 
             
                  opts = self.options
         | 
| 52 | 
            -
                  self.options = (Chef::Knife:: | 
| 57 | 
            +
                  self.options = (Chef::Knife::Bootstrap.options).merge(Chef::Knife::TopoCookbookUpload.options)
         | 
| 53 58 | 
             
                  self.options.merge!(opts)
         | 
| 54 59 |  | 
| 55 60 | 
             
                  def initialize (args)
         | 
| 56 61 | 
             
                    super
         | 
| 57 | 
            -
                    @ | 
| 62 | 
            +
                    @bootstrap_args  = initialize_cmd_args(args, [ 'bootstrap', '' ])
         | 
| 58 63 | 
             
                    @topo_upload_args  = initialize_cmd_args(args, [ 'topo', 'cookbook', 'upload', @name_args[0] ])
         | 
| 59 64 |  | 
| 60 65 | 
             
                    # All called commands need to accept union of options
         | 
| 61 | 
            -
                    Chef::Knife:: | 
| 66 | 
            +
                    Chef::Knife::Bootstrap.options = options
         | 
| 62 67 | 
             
                    Chef::Knife::TopoCookbookUpload.options = options
         | 
| 63 68 | 
             
                  end
         | 
| 64 69 |  | 
| @@ -99,20 +104,55 @@ class Chef | |
| 99 104 | 
             
                    nodes = merge_topo_properties(topo_hash['nodes'], topo_hash)
         | 
| 100 105 | 
             
                    config[:disable_editing] = true
         | 
| 101 106 |  | 
| 107 | 
            +
                    bootstrapped = []
         | 
| 108 | 
            +
                    updated = []
         | 
| 109 | 
            +
                    skipped = []
         | 
| 110 | 
            +
                    failed = [] 
         | 
| 111 | 
            +
                    
         | 
| 102 112 | 
             
                    if nodes && nodes.length > 0
         | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
                         | 
| 113 | 
            +
                             
         | 
| 114 | 
            +
                      nodes.each do |node_data|
         | 
| 115 | 
            +
                        node_name = node_data['name']
         | 
| 116 | 
            +
                        
         | 
| 117 | 
            +
                        exists = resource_exists?("nodes/#{node_name}") 
         | 
| 118 | 
            +
                        if(node_data['ssh_host'] && config[:bootstrap] && (config[:overwrite] || !exists))
         | 
| 119 | 
            +
                          if run_bootstrap(node_data, @bootstrap_args, exists)
         | 
| 120 | 
            +
                            bootstrapped << node_name
         | 
| 121 | 
            +
                          else
         | 
| 122 | 
            +
                            failed << node_name
         | 
| 123 | 
            +
                          end
         | 
| 124 | 
            +
                        else
         | 
| 125 | 
            +
                          if(exists)
         | 
| 126 | 
            +
                            updated << node_name
         | 
| 127 | 
            +
                            node = update_node(node_data)                  
         | 
| 128 | 
            +
                          else
         | 
| 129 | 
            +
                            skipped << node_name
         | 
| 130 | 
            +
                          end
         | 
| 131 | 
            +
                        end
         | 
| 132 | 
            +
                      end
         | 
| 133 | 
            +
              
         | 
| 134 | 
            +
                      ui.info("Topology #{display_name(topo_hash)} created, containing #{nodes.length} nodes")
         | 
| 135 | 
            +
                      ui.info("Build information: " + topo_hash['buildstamp']) if topo_hash['buildstamp']
         | 
| 136 | 
            +
                      
         | 
| 137 | 
            +
                      if(config[:bootstrap])
         | 
| 138 | 
            +
                        ui.info("Bootstrapped #{bootstrapped.length} nodes [ #{bootstrapped.join(', ')} ]")
         | 
| 139 | 
            +
                        if updated.length > 0
         | 
| 140 | 
            +
                          ui.info("Updated #{updated.length} nodes [ #{updated.join(', ')} ] because they already exist. " +
         | 
| 141 | 
            +
                            "Specify --overwrite to re-bootstrap existing nodes. " +
         | 
| 142 | 
            +
                            "If you are using Chef Vault, you may need to use --bootstrap-vault options in this case.")
         | 
| 143 | 
            +
                        end
         | 
| 144 | 
            +
                        ui.info("Skipped #{skipped.length} nodes [ #{skipped.join(', ')} ] because they had no ssh_host information") if skipped.length > 0
         | 
| 145 | 
            +
                      else
         | 
| 146 | 
            +
                        ui.info("Updated #{updated.length} nodes [ #{updated.join(', ')} ]")
         | 
| 147 | 
            +
                        ui.info("Skipped #{skipped.length} nodes [ #{skipped.join(', ')} ] because they do not exist") if skipped.length > 0
         | 
| 106 148 | 
             
                      end
         | 
| 107 | 
            -
                       | 
| 108 | 
            -
                       | 
| 149 | 
            +
                      
         | 
| 150 | 
            +
                      ui.warn("#{failed.length} nodes [ #{failed.join(', ')} ] failed to bootstrap due to errors") if failed.length > 0
         | 
| 151 | 
            +
                           
         | 
| 109 152 | 
             
                    else
         | 
| 110 153 | 
             
                      ui.info "No nodes found for topology #{display_name(topo_hash)}"
         | 
| 111 154 | 
             
                    end
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                    ui.info("Topology #{display_name(topo_hash)} created")
         | 
| 114 | 
            -
                    ui.info("Build information: " + topo_hash['buildstamp']) if topo_hash['buildstamp']
         | 
| 115 | 
            -
                          
         | 
| 155 | 
            +
                         
         | 
| 116 156 | 
             
                  end
         | 
| 117 157 |  | 
| 118 158 | 
             
                  include Chef::Knife::TopologyHelper      
         | 
| @@ -75,8 +75,8 @@ class Chef | |
| 75 75 | 
             
                      # load then update and save the node
         | 
| 76 76 | 
             
                      node = Chef::Node.load(node_name)
         | 
| 77 77 |  | 
| 78 | 
            -
                      if node | 
| 79 | 
            -
                        node. | 
| 78 | 
            +
                      if node['topo'] && node['topo']['name'] == @topo_name
         | 
| 79 | 
            +
                        node.rm('topo','name') 
         | 
| 80 80 | 
             
                        ui.info "Removing node #{node.name} from topology"
         | 
| 81 81 | 
             
                        node.save
         | 
| 82 82 | 
             
                      end
         | 
    
        data/lib/chef/knife/topo_list.rb
    CHANGED
    
    | @@ -37,8 +37,12 @@ class Chef | |
| 37 37 |  | 
| 38 38 | 
             
                  def run
         | 
| 39 39 |  | 
| 40 | 
            -
                     | 
| 41 | 
            -
             | 
| 40 | 
            +
                    begin
         | 
| 41 | 
            +
                      topo_bag = topo_bag_name(config[:data_bag])
         | 
| 42 | 
            +
                      output(format_list_for_display(Chef::DataBag.load(topo_bag)))
         | 
| 43 | 
            +
                    rescue Net::HTTPServerException => e
         | 
| 44 | 
            +
                      raise unless e.to_s =~ /^404/
         | 
| 45 | 
            +
                    end
         | 
| 42 46 |  | 
| 43 47 | 
             
                  end
         | 
| 44 48 |  | 
| @@ -21,6 +21,7 @@ require 'chef/node' | |
| 21 21 | 
             
            require 'chef/encrypted_data_bag_item'
         | 
| 22 22 | 
             
            require 'chef/environment'
         | 
| 23 23 | 
             
            require 'chef/knife/core/object_loader'
         | 
| 24 | 
            +
            require 'chef/rest'
         | 
| 24 25 |  | 
| 25 26 | 
             
            class Chef
         | 
| 26 27 | 
             
              class Knife
         | 
| @@ -104,7 +105,8 @@ class Chef | |
| 104 105 | 
             
                      merged_nodes = nodes ? nodes.clone : []
         | 
| 105 106 | 
             
                      merged_nodes.each do |nodeprops|
         | 
| 106 107 |  | 
| 107 | 
            -
                        normal_defaults = topo_hash['normal'] ?  | 
| 108 | 
            +
                        normal_defaults = topo_hash['normal'] ? 
         | 
| 109 | 
            +
                          Marshal.load(Marshal.dump(topo_hash['normal'])) : {}
         | 
| 108 110 | 
             
                        nodeprops['normal'] ||= {}
         | 
| 109 111 | 
             
                        nodeprops['normal'] = prop_merge!(normal_defaults, nodeprops['normal'])
         | 
| 110 112 | 
             
                        nodeprops['normal'] = prop_merge!(nodeprops['normal'], nodeprops['attributes']) if nodeprops['attributes']
         | 
| @@ -309,6 +311,55 @@ class Chef | |
| 309 311 |  | 
| 310 312 | 
             
                    version
         | 
| 311 313 | 
             
                  end
         | 
| 314 | 
            +
                  
         | 
| 315 | 
            +
                  # check if resource exists
         | 
| 316 | 
            +
                  def resource_exists?(relative_path)
         | 
| 317 | 
            +
                    rest.get_rest(relative_path)
         | 
| 318 | 
            +
                    true
         | 
| 319 | 
            +
                  rescue Net::HTTPServerException => e
         | 
| 320 | 
            +
                    raise unless e.response.code == "404"
         | 
| 321 | 
            +
                    false
         | 
| 322 | 
            +
                  end
         | 
| 323 | 
            +
                  
         | 
| 324 | 
            +
                  # Setup the bootstrap args and run the bootstrap command
         | 
| 325 | 
            +
                  def run_bootstrap(node_data, bootstrap_args, overwrite=false)
         | 
| 326 | 
            +
                    node_name = node_data['name']
         | 
| 327 | 
            +
                      
         | 
| 328 | 
            +
                    args = bootstrap_args
         | 
| 329 | 
            +
                    
         | 
| 330 | 
            +
                    # We need to remove the --bootstrap option, if it exists, because its not valid for knife bootstrap
         | 
| 331 | 
            +
                    args -= ['--bootstrap']
         | 
| 332 | 
            +
                      
         | 
| 333 | 
            +
                    # And set up the node-specific data
         | 
| 334 | 
            +
                    args += ['-N', node_name] if(node_name)
         | 
| 335 | 
            +
                    args += ['-E', node_data['chef_environment']] if(node_data['chef_environment'])
         | 
| 336 | 
            +
                    args[1] = node_data['ssh_host']
         | 
| 337 | 
            +
                    args += [ '--ssh-port', node_data['ssh_port']] if node_data['ssh_port']
         | 
| 338 | 
            +
                    args += [ '--run-list' , node_data['run_list'].join(',')] if node_data['run_list']
         | 
| 339 | 
            +
                    args += [ '--json-attributes' , node_data['normal'].to_json] if node_data['normal']
         | 
| 340 | 
            +
                    
         | 
| 341 | 
            +
                    if overwrite
         | 
| 342 | 
            +
                      ui.info("Node #{node_name} exists and will be overwritten")
         | 
| 343 | 
            +
                      # delete node first so vault refresh does not pick up existing node
         | 
| 344 | 
            +
                      begin
         | 
| 345 | 
            +
                        rest.delete("nodes/#{node_name}")
         | 
| 346 | 
            +
                        rest.delete("clients/#{node_name}")
         | 
| 347 | 
            +
                      rescue Net::HTTPServerException => e
         | 
| 348 | 
            +
                        raise unless e.response.code == "404"
         | 
| 349 | 
            +
                      end
         | 
| 350 | 
            +
                    end
         | 
| 351 | 
            +
                  
         | 
| 352 | 
            +
                    ui.info "Bootstrapping node #{node_name}"
         | 
| 353 | 
            +
                    begin
         | 
| 354 | 
            +
                      run_cmd(Chef::Knife::Bootstrap, args)
         | 
| 355 | 
            +
                      true
         | 
| 356 | 
            +
                    rescue Exception => e
         | 
| 357 | 
            +
                      raise if Chef::Config[:verbosity] == 2
         | 
| 358 | 
            +
                      ui.warn "bootstrap of node #{node_name} exited with error"
         | 
| 359 | 
            +
                      humanize_exception(e)
         | 
| 360 | 
            +
                      false
         | 
| 361 | 
            +
                    end
         | 
| 362 | 
            +
                  end
         | 
| 312 363 |  | 
| 313 364 | 
             
                end
         | 
| 314 365 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: knife-topo
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.1. | 
| 4 | 
            +
              version: 1.1.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Christine Draper
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015- | 
| 11 | 
            +
            date: 2015-12-15 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies: []
         | 
| 13 13 | 
             
            description: Knife-topo uses a JSON file to capture a topology of nodes, which can
         | 
| 14 14 | 
             
              be loaded into Chef and bootstrapped
         | 
| @@ -53,7 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 53 53 | 
             
                  version: '0'
         | 
| 54 54 | 
             
            requirements: []
         | 
| 55 55 | 
             
            rubyforge_project: 
         | 
| 56 | 
            -
            rubygems_version: 2.4. | 
| 56 | 
            +
            rubygems_version: 2.4.8
         | 
| 57 57 | 
             
            signing_key: 
         | 
| 58 58 | 
             
            specification_version: 4
         | 
| 59 59 | 
             
            summary: Knife plugin to manage topologies of nodes
         |