diff --git a/systemvm/patches/debian/config/etc/chef/node.json b/systemvm/patches/debian/config/etc/chef/node.json new file mode 100644 index 00000000000..1b23e334d41 --- /dev/null +++ b/systemvm/patches/debian/config/etc/chef/node.json @@ -0,0 +1,5 @@ +{ + "run_list": [ + "recipe[csip::default]" + ] +} diff --git a/systemvm/patches/debian/config/etc/chef/solo.rb b/systemvm/patches/debian/config/etc/chef/solo.rb new file mode 100644 index 00000000000..c7cc01d854a --- /dev/null +++ b/systemvm/patches/debian/config/etc/chef/solo.rb @@ -0,0 +1,4 @@ +data_bags_path "/var/chef/data_bags" +cookbook_path "/var/chef/cookbooks" +log_level :debug +log_location STDOUT diff --git a/systemvm/patches/debian/config/etc/init.d/cloud-early-config b/systemvm/patches/debian/config/etc/init.d/cloud-early-config index dcd49cb63d4..7d22ee71c19 100755 --- a/systemvm/patches/debian/config/etc/init.d/cloud-early-config +++ b/systemvm/patches/debian/config/etc/init.d/cloud-early-config @@ -1336,6 +1336,11 @@ STORAGE_NETMASK="" STORAGE_CIDR="" VM_PASSWORD="" +CHEF_TMP_FILE=/tmp/cmdline.json +COMMA="\t" +echo -e "{\n\"id\": \"cmdline\"," > ${CHEF_TMP_FILE} +echo -e "{\n\"cmd_line\": {" > ${CHEF_TMP_FILE} + for i in $CMDLINE do # search for foo=bar pattern and cut out foo @@ -1480,6 +1485,12 @@ for i in $CMDLINE esac done +echo -e "\n\t}\n}" >> ${CHEF_TMP_FILE} +if [ "$TYPE" != "unknown" ] +then + mv ${CHEF_TMP_FILE} /var/chef/data_bags/vr/cmd_line.json +fi + [ $ETH0_IP ] && LOCAL_ADDRS=$ETH0_IP [ $ETH0_IP6 ] && LOCAL_ADDRS=$ETH0_IP6 [ $ETH0_IP ] && [ $ETH0_IP6 ] && LOCAL_ADDRS="$ETH0_IP,$ETH0_IP6" diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/README b/systemvm/patches/debian/config/var/chef/cookbooks/README new file mode 100755 index 00000000000..3ae6f40ac5d --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/README @@ -0,0 +1,4 @@ +Location for cookbooks for the system appliances + +csip - is a provider to maintain ip associations + diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/CHANGELOG.md b/systemvm/patches/debian/config/var/chef/cookbooks/csip/CHANGELOG.md new file mode 100755 index 00000000000..b71f3bdb3ee --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/CHANGELOG.md @@ -0,0 +1,29 @@ +csip CHANGELOG +============== + +This file is used to list changes made in each version of the csip cookbook. + +License +======= + +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. + +0.1.0 +----- +- [Ian Southam] - Initial release of csip + diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/NOTES b/systemvm/patches/debian/config/var/chef/cookbooks/csip/NOTES new file mode 100644 index 00000000000..e5b409df39b --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/NOTES @@ -0,0 +1,9 @@ +TODO + +Routes + +Default Route (work out differences between VR and VPCr) + +Adding marks via ip rule +ie. ip rule add fwmark $tableNo table $tableName + diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/README.md b/systemvm/patches/debian/config/var/chef/cookbooks/csip/README.md new file mode 100755 index 00000000000..8683f9cbe60 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/README.md @@ -0,0 +1,15 @@ +csip Cookbook +============= +TODO: Cookbook to configure and maintain ip associations for VPCr and Vr + +Requirements +------------ +This is specifically designed to run insode the Virtual router and VPC router appliances in Apache Cloudstack + +Contributing +------------ + +License and Authors +------------------- +Authors: +Issued under the Apache 2.0 license diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/attributes/route.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/attributes/route.rb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/ian.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/ian.rb new file mode 100755 index 00000000000..e0811183d82 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/ian.rb @@ -0,0 +1,5 @@ +require 'ipaddr' +require 'pp' + +a = IPAddr.new("10.0.2.180") +pp a.mask("255.255.255.128").to_s diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/libraries/helper.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/libraries/helper.rb new file mode 100644 index 00000000000..bbb2f5bcce0 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/libraries/helper.rb @@ -0,0 +1,70 @@ +# ----------------------------------------------------------- # +# Helper functions for the cookbook +# +# listIps will return a list of IPs/devices that should be +# deleted +# ----------------------------------------------------------- # +require 'ipaddr' + +def listIPs(ips) + # ----------------------------------------------------------- # + # Collect all configured ip4 interfaces on the machine and + # compare it to the cloudstack configuration + # Returns a hash containing any ip/device combinations + # that should not be there + # ----------------------------------------------------------- # + ipList = Hash.new + cmd = Mixlib::ShellOut.new("ip addr show") + cmd.run_command + if cmd.exitstatus == 0 + cmd.stdout.each_line do |line| + next unless line.include? "inet " + bits = line.strip.split(/ /) + # For now do not mess with the control interface + next if bits[-1] == "lo" or bits[-1] == "eth0" + if ! inConfig(ips, bits[-1], bits[1]) + ipList[ bits[-1] ] = bits[1] + end + end + end + return ipList +end + +def inConfig(ips, dev, tip) + # ----------------------------------------------------------- # + # Returns true if the ip/dev combination is in the config + # Returns false if it is not + # ----------------------------------------------------------- # + if ips[dev].nil? + return false + end + ips[dev].each do |o| + oip = o['publicIp'] + '/' << IPAddr.new(o['vlanNetmask']).to_i.to_s(2).count("1").to_s + if oip == tip + return true + end + end + return false +end + +def execute(cmdStr) + cmd = Mixlib::ShellOut.new("#{cmdStr}") + cmd.run_command + #puts "\n#{cmdStr} #{cmdPar} #{cmd.status}" + cmd.exitstatus == 0 +end + +def executeReturn(cmdStr) + cmd = Mixlib::ShellOut.new("#{cmdStr}") + cmd.run_command + #puts "\n#{cmdStr} #{cmdPar} #{cmd.status}" + cmd.stdout.split(/\n/) +end + +def calculateNetwork(ip, mask) + return IPAddr.new(ip).mask(mask).to_s +end + +def calculateCIDRMask(mask) + return IPAddr.new( mask ).to_i.to_s(2).count("1").to_s +end diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/metadata.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/metadata.rb new file mode 100755 index 00000000000..f25422619e7 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/metadata.rb @@ -0,0 +1,7 @@ +name 'csip' +maintainer 'Apache Cloudstack' +maintainer_email 'dev@cloudstack.apache.org' +license 'Apache 2.0' +description 'Installs/Configures csip' +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version '0.1.0' diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/default.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/default.rb new file mode 100644 index 00000000000..5e747a6d2f5 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/default.rb @@ -0,0 +1,5 @@ +action :create do + file "/root/testing" do + mode '644' + end +end diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/device.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/device.rb new file mode 100755 index 00000000000..2ae0048929d --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/device.rb @@ -0,0 +1,118 @@ +require 'ipaddr' + +action :create do + if @current_resource.exists + Chef::Log.info "#{ @new_resource.device } already configured - nothing to do." + else + converge_by("Setting up #{ @new_resource }") do + plumbDevice + end + end +end + +action :delete do + if @current_resource.exists + converge_by("Removing #{ @new_resource }") do + unPlumbDevice + end + else + Chef::Log.info "#{ @new_resource.device } not configured - nothing to do." + end +end + +def load_current_resource + @current_resource = Chef::Resource::CsipDevice.new(@new_resource.name) + @current_resource.index(@new_resource.index) + @current_resource.name(@new_resource.name) + @current_resource.bdev(@new_resource.bdev) + @current_resource.object(@new_resource.object) + @current_resource.exists = false + if new_resource.cidrs.nil? + @current_resource.cidrs(new_resource.object['publicIp'] + '/' + IPAddr.new( new_resource.object['vlanNetmask']).to_i.to_s(2).count("1").to_s) + else + @current_resource.cidrs(@new_resource.cidrs) + end + if device_exists? + @current_resource.exists = true + end +end + +def device_exists? + current_resource.device = current_resource.bdev + if current_resource.index > 0 + current_resource.device = current_resource.device + ':' + current_resource.index.to_s + end + if not checkDevice + Chef::Log.error "#{ current_resource.bdev } not present cannot configure" + return true + end + deviceUp? + correctIP? + correctConntrack? + return current_resource.up && current_resource.configured && current_resource.contrack +end + +def plumbDevice + if ! current_resource.configured + if ! execute("ip addr add dev #{current_resource.device} #{current_resource.cidrs} brd +") + Chef::Log.error "#{ @new_resource.device } failed to configure ip on interface" + return false + end + end + if ! current_resource.up + if ! execute("ip link set #{current_resource.device} up") + Chef::Log.error "#{ @new_resource.device } failed to bring interface up" + return false + end + end + if ! current_resource.contrack + if ! execute("iptables -t mangle -A PREROUTING -i #{current_resource.device} -m state --state NEW -j CONNMARK --set-mark #{current_resource.object['nicDevId']}") + Chef::Log.error "#{ @new_resource.device } failed to set set conmark" + return false + end + end + execute("arping -c 1 -I #{current_resource.device} -A -U -s #{current_resource.object['publicIp']} #{current_resource.object['publicIp']}") + execute("arping -c 1 -I #{current_resource.device} -A -U -s #{current_resource.object['publicIp']} #{current_resource.object['publicIp']}") + return true +end + +def unPlumbDevice + pp "ip addr del dev #{current_resource.device} #{current_resource.cidrs}" + if ! execute("ip addr del dev #{current_resource.device} #{current_resource.cidrs}") + Chef::Log.error "#{ @new_resource.device } failed to delete ip on interface" + return false + end + return true +end + +def correctConntrack? + current_resource.contrack = execute("iptables-save -t mangle | grep \"PREROUTING -i #{current_resource.bdev} -m state --state NEW -j CONNMARK --set-xmark\"") + return current_resource.contrack +end + +def correctIP? + current_resource.configured = execute("ip addr show #{current_resource.bdev} | grep #{current_resource.cidrs}") + return current_resource.configured +end + +def deviceUp? + current_resource.up = ! execute("ip link show #{current_resource.device} | grep DOWN") + return current_resource.up +end + +def checkDevice + file = ::File.open("/proc/net/dev") + attempts = 0 + found = false + until attempts > 15 or found do + ::File.readlines(file).each do |line| + if line.include? "#{current_resource.bdev}:" + found = true + end + end + attempts += 1 + sleep(1) + end + file.close + return found +end diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/route.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/route.rb new file mode 100644 index 00000000000..c2c4aaa6f42 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/providers/route.rb @@ -0,0 +1,105 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# ip route flush cache +# +action :create do + if @current_resource.exists + Chef::Log.info "#{ @new_resource.dev } already exists - nothing to do." + else + converge_by("Creating route for #{ @new_resource }") do + createRoute + end + end +end + +action :delete do + +end + +def load_current_resource + @current_resource = Chef::Resource::CsipRoute.new(@new_resource.name) + @current_resource.exists = false + @current_resource.ip(@new_resource.ip) + @current_resource.mask(@new_resource.mask) + @current_resource.dev(@new_resource.dev) + @current_resource.table(@new_resource.table) + @current_resource.type(@new_resource.type) + @current_resource.network(calculateNetwork(@new_resource.ip,@new_resource.mask)) + @current_resource.cidrm(calculateCIDRMask(@new_resource.mask)) + if device_exists? + @current_resource.exists = true + end +end + +def device_exists? + Chef::Log.debug "Checking for existence of routing table" + @current_resource.tableExists = checkTableExists + Chef::Log.debug "Checking for existence of route" + if @current_resource.type == "dev" + @current_resource.routeExists = typeDevExists() + return @current_resource.routeExists && @current_resource.tableExists + end + if @current_resource.type == "default" + @current_resource.routeExists = typeDefaultExists() + return @current_resource.routeExists && @current_resource.tableExists + end + Chef::Log.error "Cannot provision a route of type #{current_resource.type}" + # Route cannot exist if the table does not but let us be belt and braces about this + return true && @current_resource.tableExists +end + +def checkTableExists + file="/etc/iproute2/rt_tables" + ::File.readlines(file).each do |line| + next if line =~ /^#/ + next if ! line.include? "#{@current_resource.dev[3,1]} #{@current_resource.table}" + return true + end + return false +end + +def typeDevExists + executeReturn("ip route show table #{@current_resource.table} dev #{current_resource.dev}").each do |line| + next if ! line.include? "proto static" + next if ! line.include? "#{current_resource.network}/#{current_resource.cidrm}" + return true + end + return false +end + +def typeDefaultExists + executeReturn("ip route show table #{@current_resource.table} dev #{@current_resource.dev} via #{@current_resource.ip}").each do |line| + next if ! line.include? "default" + return true + end + return false +end + +def createRoute + if(! @current_resource.tableExists) + execute(" echo #{@current_resource.dev[3,1]} #{@current_resource.table} >> /etc/iproute2/rt_tables") + end + if(! @current_resource.routeExists) + if(@current_resource.type == "dev") + execute("ip route add #{current_resource.network}/#{current_resource.cidrm} dev #{current_resource.dev} table #{current_resource.table} proto static") + end + if(@current_resource.type == "default") + execute("ip route add default via #{current_resource.ip} table #{current_resource.table} proto static") + end + end +end diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/recipes/default.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/recipes/default.rb new file mode 100755 index 00000000000..5a5cad302cf --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/recipes/default.rb @@ -0,0 +1,70 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +begin + vr_ips = data_bag_item('vr', 'ips') +rescue + raise format('Cannot find the %s databag item within the %s databag. Please correct this', 'vr', 'ips') +end + +# List configured ips on this node and remove any that are not in the configuration +listIPs(vr_ips).each do |dev, ip| + csip_device "#{dev}-#{ip}" do + action :delete + cidrs ip + index 0 + bdev dev + end +end + +vr_ips.each do |name,data| + next unless data.class == Array + next unless data.length > 0 + idx = 0 + data.each do |ipo| + csip_device "#{name}-#{idx}" do + object ipo + index idx + bdev name + end + idx += 1 + end +end + +# Add an necessary routes +# This could be embedded in the device recipe is done like that for self healing purposes +vr_ips.each do |name,data| + next unless data.class == Array + next unless data.length > 0 + # ip route add $subnet/$mask dev $ethDev table $tableName proto static + data.each do |ipo| + csip_route "#{name}-dev" do + type "dev" + table "Table_#{name}" + ip ipo['publicIp'] + mask ipo['vlanNetmask'] + dev name + end + csip_route "#{name}-default" do + type "default" + table "Table_#{name}" + ip ipo['vlanGateway'] + mask ipo['vlanNetmask'] + dev name + end + end +end diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/default.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/default.rb new file mode 100644 index 00000000000..d6c0e4ea377 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/default.rb @@ -0,0 +1,4 @@ +default_action(:create) + +attribute(:id) +attribute(:address) diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/device.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/device.rb new file mode 100755 index 00000000000..867989047c3 --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/device.rb @@ -0,0 +1,14 @@ +actions :create, :delete +default_action(:create) + +attribute(:device) +attribute(:object) +attribute(:cidrs) +attribute(:index) +attribute(:bdev) + +attr_accessor :exists +attr_accessor :up +attr_accessor :contrack +attr_accessor :configured +attr_accessor :device diff --git a/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/route.rb b/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/route.rb new file mode 100755 index 00000000000..68ad309765f --- /dev/null +++ b/systemvm/patches/debian/config/var/chef/cookbooks/csip/resources/route.rb @@ -0,0 +1,35 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +actions :create, :delete +default_action(:create) + +# dev default +attribute(:type) +attribute(:table) +attribute(:ip) +attribute(:mask) +attribute(:gateway) +attribute(:dev) +attribute(:network) +attribute(:cidrm) +attribute(:tableExists) +attribute(:routeExists) + +attr_accessor :exists +attr_accessor :tableExists +attr_accessor :routeExists diff --git a/tools/appliance/definitions/systemvmtemplate/chef.sh b/tools/appliance/definitions/systemvmtemplate/chef.sh new file mode 100644 index 00000000000..d4637d8da56 --- /dev/null +++ b/tools/appliance/definitions/systemvmtemplate/chef.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -e +set -x + +function install_chef() { + curl -L https://www.opscode.com/chef/install.sh | sudo bash +} + +return 2>/dev/null || install_chef diff --git a/tools/appliance/definitions/systemvmtemplate/definition.rb b/tools/appliance/definitions/systemvmtemplate/definition.rb index f5d48504d36..67825aa58f9 100644 --- a/tools/appliance/definitions/systemvmtemplate/definition.rb +++ b/tools/appliance/definitions/systemvmtemplate/definition.rb @@ -88,6 +88,7 @@ config = { '../../cloud_scripts_shar_archive.sh', 'configure_systemvm_services.sh', 'authorized_keys.sh', + 'chef.sh', 'configure_persistent_config.sh', # cleanup & space-saving 'cleanup.sh',