diff options
author | 2017-09-19 14:01:21 +0000 | |
---|---|---|
committer | 2017-09-19 14:01:21 +0000 | |
commit | 7e83d7fbdb6975f7b9e47284aacc833749853d62 (patch) | |
tree | 72ba5458965d17025133d2136ab44581405b10fd /bootstrap/vagrant-onap/Vagrantfile | |
parent | 7e53fd67fc22006222d2a153da8c4eb812bfa3ed (diff) | |
parent | 461238604ba4ac220aceb37c3081a71aa7834d22 (diff) |
Merge "vagrant-onap vagrant file improvements"
Diffstat (limited to 'bootstrap/vagrant-onap/Vagrantfile')
-rw-r--r-- | bootstrap/vagrant-onap/Vagrantfile | 681 |
1 files changed, 345 insertions, 336 deletions
diff --git a/bootstrap/vagrant-onap/Vagrantfile b/bootstrap/vagrant-onap/Vagrantfile index 8417cc953..adc73ca0d 100644 --- a/bootstrap/vagrant-onap/Vagrantfile +++ b/bootstrap/vagrant-onap/Vagrantfile @@ -1,8 +1,9 @@ # -*- mode: ruby -*- # vi: set ft=ruby : -conf = { -# Generic parameters used across all ONAP components + +configuration = { + # Generic parameters used across all ONAP components 'public_net_id' => '00000000-0000-0000-0000-000000000000', 'key_name' => 'ecomp_key', 'pub_key' => '', @@ -32,379 +33,387 @@ conf = { 'enable_oparent' => 'True' } -Vagrant.require_version ">= 1.8.6" -# Determine the OS for the host computer -module OS - def OS.windows? - (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil - end +box = { + :virtualbox => 'ubuntu/trusty64', + :libvirt => 'sputnik13/trusty64', + :openstack => nil +} - def OS.mac? - (/darwin/ =~ RUBY_PLATFORM) != nil - end - def OS.unix? - !OS.windows? - end +nodes = [ + { + :name => "aai", + :ips => ['10.252.0.6', "192.168.50.6"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["aai"] + }, + { + :name => "all-in-one", + :ips => ['10.252.0.3', "192.168.50.3"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 12 * 1024, + :groups => ["all-in-one"], + :flavor => 'm1.xlarge', + :args => ['mr', 'sdc', 'aai', 'mso', 'robot', 'vid', 'sdnc', 'portal', 'dcae', 'policy', 'appc', 'vfc', 'ccsdk'], + }, + { + :name => "appc", + :ips => ['10.252.0.14', "192.168.50.14"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["appc"], + }, + { + :name => "ccsdk", + :ips => ['10.252.0.14', "192.168.50.17"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["ccsdk"], + }, + { + :name => "dcae", + :ips => ['10.252.0.12', "192.168.50.12"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["dcae"], + }, + { + :name => "dns", + :ips => ['10.252.0.3', "192.168.50.3"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 1 * 1024, + :groups => ["individual"], + :flavor => 'm1.small', + :args => [" "] + }, + { + :name => "message-router", + :ips => ['10.252.0.4', "192.168.50.4"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["mr"], + }, + { + :name => "mso", + :ips => ['10.252.0.7', "192.168.50.7"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["mso"], + }, + { + :name => "multicloud", + :ips => ['10.252.0.16', "192.168.50.16"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["multicloud"], + }, + { + :name => "policy", + :ips => ['10.252.0.13', "192.168.50.13"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["policy"], + }, + { + :name => "portal", + :ips => ['10.252.0.11', "192.168.50.11"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["portal"], + }, + { + :name => "robot", + :ips => ['10.252.0.8', "192.168.50.8"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["robot"], + }, + { + :name => "sdc", + :ips => ['10.252.0.5', "192.168.50.5"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 8 * 1024, + :groups => ["individual"], + :args => ["sdc"], + }, + { + :name => "sdnc", + :ips => ['10.252.0.10', "192.168.50.10"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ["sdnc"], + }, + { + :name => "testing", + :ips => ['10.252.0.3', "192.168.50.3"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["testing"], + :flavor => 'm1.small', + :args => [""], + }, + { + :name => "vfc", + :ips => ['10.252.0.15', "192.168.50.15"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ['vfc'], + }, + + { + :name => "vid", + :ips => ['10.252.0.9', "192.168.50.9"], + :macs => [], + :cpus => 2, + :cpu => "50", + :ram => 4 * 1024, + :groups => ["individual"], + :args => ['vid'], + }, +] - def OS.linux? - OS.unix? and not OS.mac? - end -end -if OS.windows? - puts "Vagrant launched from windows. This configuration has not fully tested." -end +run_path = 'vagrant_utils/postinstall.sh' + +sdc_volume='vol1-sdc-data.vdi' + +Vagrant.require_version ">= 1.8.6" # Determine the provider used provider = (ENV['VAGRANT_DEFAULT_PROVIDER'] || :virtualbox).to_sym -puts "Using #{provider} provider" +puts "[INFO] Provider: #{provider} " + vd_conf = ENV.fetch('VD_CONF', 'etc/settings.yaml') if File.exist?(vd_conf) require 'yaml' user_conf = YAML.load_file(vd_conf) - conf.update(user_conf) + configuration.update(user_conf) end -deploy_mode = ENV.fetch('DEPLOY_MODE', 'individual') -sdc_volume='vol1-sdc-data.vdi' +#Set network interface +is_windows = Gem.win_platform? +if is_windows + net_interface = 'VirtualBox Host-Only Ethernet Adapter #2' +else + net_interface = 'vboxnet0' +end +puts "[INFO] Net interface: #{net_interface}" -Vagrant.configure("2") do |config| - if ENV['http_proxy'] != nil and ENV['https_proxy'] != nil and ENV['no_proxy'] != nil - if not Vagrant.has_plugin?('vagrant-proxyconf') - system 'vagrant plugin install vagrant-proxyconf' - raise 'vagrant-proxyconf was installed but it requires to execute again' - end - config.proxy.http = ENV['http_proxy'] - config.proxy.https = ENV['https_proxy'] - config.proxy.no_proxy = ENV['no_proxy'] - end - - if Vagrant.has_plugin?('vagrant-vbguest') - puts 'vagrant-vbguest auto_update feature will be disable to avoid sharing conflicts' - config.vbguest.auto_update = false - end - - config.vm.box = 'ubuntu/trusty64' - if provider == :libvirt - config.vm.box = 'sputnik13/trusty64' - if not Vagrant.has_plugin?('vagrant-libvirt') - system 'vagrant plugin install vagrant-libvirt' - raise 'vagrant-libvirt was installed but it requires to execute again' - end - end - if provider == :openstack - config.vm.box = nil - config.ssh.username = 'ubuntu' - if not Vagrant.has_plugin?('vagrant-openstack-provider') - system 'vagrant plugin install vagrant-openstack-provider' - raise 'vagrant-openstack-provider was installed but it requires to execute again' - end - end - #config.vm.provision "docker" - config.vm.synced_folder './opt', '/opt/', create: true - config.vm.synced_folder './lib', '/var/onap/', create: true - config.vm.synced_folder '~/.m2', '/root/.m2/', create: true - - config.vm.provider :virtualbox do |v| - v.customize ["modifyvm", :id, "--memory", 4 * 1024] - end - config.vm.provider :libvirt do |v| - v.memory = 4 * 1024 - v.nested = true - end - config.vm.provider :openstack do |v| - - v.openstack_auth_url = ENV.fetch('OS_AUTH_URL', '') - v.tenant_name = ENV.fetch('OS_TENANT_NAME', '') - v.username = ENV.fetch('OS_USERNAME', '') - v.password = ENV.fetch('OS_PASSWORD', '') - v.region = ENV.fetch('OS_REGION_NAME', '') - v.identity_api_version = ENV.fetch('OS_IDENTITY_API_VERSION', '') - v.domain_name = ENV.fetch('OS_PROJECT_DOMAIN_ID', '') - v.project_name = ENV.fetch('OS_PROJECT_NAME', '') - - v.floating_ip_pool = ENV.fetch('OS_FLOATING_IP_POOL', '') - v.floating_ip_pool_always_allocate = (ENV['OS_FLOATING_IP_ALWAYS_ALLOCATE'] == 'true') - v.image = ENV.fetch('OS_IMAGE', '') - v.security_groups = [ENV.fetch('OS_SEC_GROUP', '')] - v.flavor = 'm1.medium' - v.networks = ENV.fetch('OS_NETWORK', '') - end - - case deploy_mode - - when 'all-in-one' - - config.vm.define :all_in_one do |all_in_one| - all_in_one.vm.hostname = 'all-in-one' - all_in_one.vm.network :private_network, ip: '192.168.50.3' - all_in_one.vm.provider "virtualbox" do |v| - v.customize ["modifyvm", :id, "--memory", 12 * 1024] - unless File.exist?(sdc_volume) - v.customize ['createhd', '--filename', sdc_volume, '--size', 20 * 1024] - end - v.customize ['storageattach', :id, '--storagectl', 'SATAController', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', sdc_volume] - end - all_in_one.vm.provider "libvirt" do |v| - v.memory = 12 * 1024 - v.nested = true - v.storage :file, path: sdc_volume, bus: 'sata', device: 'vdb', size: '2G' - end - all_in_one.vm.provider "openstack" do |v| - v.server_name = 'all-in-one' - v.flavor = 'm1.xlarge' - end - all_in_one.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['mr', 'sdc', 'aai', 'mso', 'robot', 'vid', 'sdnc', 'portal', 'dcae', 'policy', 'appc', 'vfc', 'ccsdk'] - s.env = conf - end - end - - when 'individual' +#If argument is given use it. Otherwise use Env: DEPLOY_MODE else use default +requested_machine = ARGV[1] - config.vm.define :dns do |dns| - dns.vm.hostname = 'dns' - dns.vm.network :private_network, ip: '192.168.50.3' - dns.vm.provider "virtualbox" do |v| - v.customize ["modifyvm", :id, "--memory", 1 * 1024] - end - dns.vm.provider "libvirt" do |v| - v.memory = 1 * 1024 - v.nested = true - end - dns.vm.provider "openstack" do |v| - v.server_name = 'dns' - v.flavor = 'm1.small' - end - dns.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.env = conf - end +deploy_mode = ENV.fetch('DEPLOY_MODE', 'individual') +if requested_machine != nil + if requested_machine.include?("all-in-one") || requested_machine.include?("testing") + deploy_mode = requested_machine end +end - config.vm.define :mr do |mr| - mr.vm.hostname = 'message-router' - mr.vm.network :private_network, ip: '192.168.50.4' - mr.vm.provider "openstack" do |v| - v.server_name = 'message-router' - end - mr.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['mr'] - s.env = conf - end - end +#Catch the status of all machines +if ARGV[0] == 'status' || ARGV[0] == 'destroy' + deploy_mode = 'NA' +end - config.vm.define :sdc do |sdc| - sdc.vm.hostname = 'sdc' - sdc.vm.network :private_network, ip: '192.168.50.5' - sdc.vm.provider "virtualbox" do |v| - unless File.exist?(sdc_volume) - v.customize ['createhd', '--filename', sdc_volume, '--size', 20 * 1024] - end - v.customize ['storageattach', :id, '--storagectl', 'SATAController', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', sdc_volume] - end - sdc.vm.provider "libvirt" do |v| - v.storage :file, path: sdc_volume, bus: 'sata', device: 'vdb', size: '2G' - end - sdc.vm.provider "openstack" do |v| - v.server_name = 'sdc' - end - sdc.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['sdc'] - s.env = conf - end - end +puts "[INFO] Deploy Mode: #{deploy_mode}" - config.vm.define :aai do |aai| - aai.vm.hostname = 'aai' - aai.vm.network :private_network, ip: '192.168.50.6' - aai.vm.provider "openstack" do |v| - v.server_name = 'aai' - end - aai.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['aai'] - s.env = conf - end - end +#In case of all-in-one or testing clean the nodes list +case deploy_mode + when 'all-in-one' + nodes.select! do |node| + if node[:name].include?("all-in-one") + true if node[:name] + end + end - config.vm.define :mso do |mso| - mso.vm.hostname = 'mso' - mso.vm.network :private_network, ip: '192.168.50.7' - mso.vm.provider "openstack" do |v| - v.server_name = 'mso' - end - mso.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['mso'] - s.env = conf - end - end - - config.vm.define :robot do |robot| - robot.vm.hostname = 'robot' - robot.vm.network :private_network, ip: '192.168.50.8' - robot.vm.provider "openstack" do |v| - v.server_name = 'robot' - end - robot.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['robot'] - s.env = conf - end - end + when 'individual' + nodes.select! do |node| + if node[:groups][0].include?("individual") + true if node[:name] + + end + end - config.vm.define :vid do |vid| - vid.vm.hostname = 'vid' - vid.vm.network :private_network, ip: '192.168.50.9' - vid.vm.provider "openstack" do |v| - v.server_name = 'vid' - end - vid.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['vid'] - s.env = conf - end - end + when 'testing' + nodes.select! do |node| + if node[:name].include?("testing") + true if node[:name] + end + end +end - config.vm.define :sdnc do |sdnc| - sdnc.vm.hostname = 'sdnc' - sdnc.vm.network :private_network, ip: '192.168.50.10' - sdnc.vm.provider "openstack" do |v| - v.server_name = 'sdnc' - end - sdnc.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['sdnc'] - s.env = conf - end - end +Vagrant.configure("2") do |config| - config.vm.define :portal do |portal| - portal.vm.hostname = 'portal' - portal.vm.network :private_network, ip: '192.168.50.11' - portal.vm.provider "openstack" do |v| - v.server_name = 'portal' - end - portal.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['portal'] - s.env = conf + # PROXY definitions + if ENV['http_proxy'] != nil and ENV['https_proxy'] != nil and ENV['no_proxy'] != nil + if not Vagrant.has_plugin?('vagrant-proxyconf') + system 'vagrant plugin install vagrant-proxyconf' + raise 'vagrant-proxyconf was installed but it requires to execute again' end + config.proxy.http = ENV['http_proxy'] + config.proxy.https = ENV['https_proxy'] + config.proxy.no_proxy = ENV['no_proxy'] end - config.vm.define :dcae do |dcae| - dcae.vm.hostname = 'dcae' - dcae.vm.network :private_network, ip: '192.168.50.12' - dcae.vm.provider "openstack" do |v| - v.server_name = 'dcae' - end - dcae.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['dcae'] - s.env = conf - end + if Vagrant.has_plugin?('vagrant-vbguest') + puts 'vagrant-vbguest auto_update feature will be disable to avoid sharing conflicts' + config.vbguest.auto_update = false end - config.vm.define :policy do |policy| - policy.vm.hostname = 'policy' - policy.vm.network :private_network, ip: '192.168.50.13' - policy.vm.provider "openstack" do |v| - v.server_name = 'policy' - end - policy.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['policy'] - s.env = conf + if provider == :libvirt + if not Vagrant.has_plugin?('vagrant-libvirt') + system 'vagrant plugin install vagrant-libvirt' + raise 'vagrant-libvirt was installed but it requires to execute again' end end - - config.vm.define :appc do |appc| - appc.vm.hostname = 'appc' - appc.vm.network :private_network, ip: '192.168.50.14' - appc.vm.provider "openstack" do |v| - v.server_name = 'appc' - end - appc.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['appc'] - s.env = conf + if provider == :openstack + config.ssh.username = 'ubuntu' + if not Vagrant.has_plugin?('vagrant-openstack-provider') + system 'vagrant plugin install vagrant-openstack-provider' + raise 'vagrant-openstack-provider was installed but it requires to execute again' end end - config.vm.define :vfc do |vfc| - vfc.vm.hostname = 'vfc' - vfc.vm.network :private_network, ip: '192.168.50.15' - vfc.vm.provider "openstack" do |v| - v.server_name = 'vfc' - end - vfc.vm.provision 'docker' - vfc.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['vfc'] - s.env = conf - end - end + nodes.each do |node| + config.vm.define node[:name] do |nodeconfig| + + # Common Settings: + + nodeconfig.vm.provider "virtualbox" do |vbox| + vbox.customize ['modifyvm', :id, '--nictype1', 'virtio'] + vbox.customize ['modifyvm', :id, '--audio', 'none'] + vbox.customize ['modifyvm', :id, '--vram', '1'] + vbox.customize ['modifyvm', :id, "--cpuhotplug", "off"] + vbox.customize ['modifyvm', :id, "--cpuexecutioncap", node[:cpu]] + vbox.customize ['modifyvm', :id, "--cpus", node[:cpus]] + vbox.customize ["modifyvm", :id, "--memory", node[:ram]] + end + + nodeconfig.vm.provider "libvirt" do |lbox| + lbox.memory = node[:ram] + lbox.nested = true + end + + nodeconfig.vm.provider :openstack do |obox| + obox.openstack_auth_url = ENV.fetch('OS_AUTH_URL', '') + obox.tenant_name = ENV.fetch('OS_TENANT_NAME', '') + obox.username = ENV.fetch('OS_USERNAME', '') + obox.password = ENV.fetch('OS_PASSWORD', '') + obox.region = ENV.fetch('OS_REGION_NAME', '') + obox.identity_api_version = ENV.fetch('OS_IDENTITY_API_VERSION', '') + obox.domain_name = ENV.fetch('OS_PROJECT_DOMAIN_ID', '') + obox.project_name = ENV.fetch('OS_PROJECT_NAME', '') + obox.floating_ip_pool = ENV.fetch('OS_FLOATING_IP_POOL', '') + obox.floating_ip_pool_always_allocate = (ENV['OS_FLOATING_IP_ALWAYS_ALLOCATE'] == 'true') + obox.image = ENV.fetch('OS_IMAGE', '') + obox.security_groups = [ENV.fetch('OS_SEC_GROUP', '')] + obox.networks = ENV.fetch('OS_NETWORK', '') + obox.flavor = node[:flavor] + obox.server_name = node[:name] - config.vm.define :multicloud do |multicloud| - multicloud.vm.hostname = 'multicloud' - multicloud.vm.network :private_network, ip: '192.168.50.16' - multicloud.vm.provider "openstack" do |v| - v.server_name = 'multicloud' - end - multicloud.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['multicloud'] - s.env = conf - end - end + end - config.vm.define :ccsdk do |ccsdk| - ccsdk.vm.hostname = 'ccsdk' - ccsdk.vm.network :private_network, ip: '192.168.50.17' - ccsdk.vm.provider "openstack" do |v| - v.server_name = 'ccsdk' - end - ccsdk.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/postinstall.sh' - s.args = ['ccsdk'] - s.env = conf - end - end + # Set Box type + nodeconfig.vm.box = box[provider] + + # Set Node name + nodeconfig.vm.hostname = node[:name] + + # Set Sync Folder + nodeconfig.vm.synced_folder ".", "/vagrant", disabled: true + nodeconfig.vm.synced_folder './opt', '/opt/', create: true + nodeconfig.vm.synced_folder './lib', '/var/onap/', create: true + if !is_windows + nodeconfig.vm.synced_folder '~/.m2', '/root/.m2/', create: true + end + # Set Network + nodeconfig.vm.network :private_network, ip: node[:ips][1] + + # Specific settings: + + #Set Storage (For SDC or All-in-one) + if node[:name].include?("all-in-one") || node[:name].include?("sdc") + nodeconfig.vm.provider "virtualbox" do |v| + unless File.exist?(sdc_volume) + v.customize ['createhd', '--filename', sdc_volume, '--size', 20 * 1024] + end + v.customize ['storageattach', :id, '--storagectl', 'SATAController', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', sdc_volume] + end + + nodeconfig.vm.provider "libvirt" do |v| + v.storage :file, path: sdc_volume, bus: 'sata', device: 'vdb', size: '2G' + end + end + + + if node[:name].include? "testing" + nodeconfig.vm.synced_folder './tests', '/var/onap_tests/', create: true + test_suite = ENV.fetch('TEST_SUITE', '*') + test_case = ENV.fetch('TEST_CASE', '*') + # Override variables + run_path = 'vagrant_utils/unit_testing.sh' + node[:args] = [test_suite, test_case] + end - when 'testing' - config.vm.define :testing do |testing| - test_suite = ENV.fetch('TEST_SUITE', '*') - test_case = ENV.fetch('TEST_CASE', '*') + if node[:name].include? "vfc" + nodeconfig.vm.provision 'docker' + end - testing.vm.hostname = 'testing' - testing.vm.network :private_network, ip: '192.168.50.3' - testing.vm.synced_folder './tests', '/var/onap_tests/', create: true - testing.vm.provider "virtualbox" do |v| - v.customize ["modifyvm", :id, "--memory", 4 * 1024] - end - testing.vm.provider "libvirt" do |v| - v.memory = 4 * 1024 - v.nested = true - end - testing.vm.provider "openstack" do |v| - v.server_name = 'testing' - v.flavor = 'm1.small' - end - testing.vm.provision 'shell' do |s| - s.path = 'vagrant_utils/unit_testing.sh' - s.args = [test_suite, test_case] - s.env = conf - end - end + nodeconfig.vm.provision 'shell' do |s| + s.path = run_path + s.args = node[:args] + s.env = configuration + end - end -end + end #nodeconfig + end #node +end #config + |