You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2017/12/16 06:46:03 UTC
[cloudstack] 10/34: CLOUDSTACK-10013: Make the generated VR/json
files unique (ports #1470)
This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch debian9-systemvmtemplate
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 6ea2717edad57cf2cd7a61edf93a3dc07eeda1be
Author: Remi Bergsma <gi...@remi.nl>
AuthorDate: Sat Dec 2 23:19:14 2017 +0530
CLOUDSTACK-10013: Make the generated VR/json files unique (ports #1470)
This ports PR #1470 by @remibergsma.
Make the generated json files unique to prevent concurrency issues:
The json files now have UUIDs to prevent them from getting overwritten
before they've been executed. Prevents config to be pushed to the wrong
router.
2016-02-25 18:32:23,797 DEBUG [c.c.a.t.Request] (AgentManager-Handler-1:null) (logid:) Seq 2-4684025087442026584: Processing: { Ans: , MgmtId: 90520732674657, via: 2, Ver: v1, Flags: 10, [{"com.cloud.agent.api.routing.GroupA
nswer":{"results":["null - success: null","null - success: [INFO] update_config.py :: Processing incoming file => vm_dhcp_entry.json.4ea45061-2efb-4467-8eaa-db3d77fb0a7b\n[INFO] Processing JSON file vm_dhcp_entry.json.4ea4506
1-2efb-4467-8eaa-db3d77fb0a7b\n"],"result":true,"wait":0}}] }
On the router:
2016-02-25 18:32:23,416 merge.py __moveFile:298 Processed file written to /var/cache/cloud/processed/vm_dhcp_entry.json.4ea45061-2efb-4467-8eaa-db3d77fb0a7b.gz
Signed-off-by: Rohit Yadav <ro...@shapeblue.com>
---
.../facade/AbstractConfigItemFacade.java | 21 +-
.../kvm/resource/LibvirtComputingResource.java | 5 +
systemvm/patches/debian/etc/rc.local | 9 -
systemvm/patches/debian/opt/cloud/bin/configure.py | 220 +++++++++------------
systemvm/patches/debian/opt/cloud/bin/merge.py | 37 ++--
.../patches/debian/opt/cloud/bin/update_config.py | 22 ++-
6 files changed, 159 insertions(+), 155 deletions(-)
diff --git a/core/src/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java b/core/src/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java
index f017384..a083012 100644
--- a/core/src/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java
+++ b/core/src/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java
@@ -22,6 +22,8 @@ package com.cloud.agent.resource.virtualnetwork.facade;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
+import java.util.UUID;
+import org.apache.log4j.Logger;
import com.cloud.agent.api.BumpUpPriorityCommand;
import com.cloud.agent.api.SetupGuestNetworkCommand;
@@ -58,6 +60,8 @@ import com.google.gson.GsonBuilder;
public abstract class AbstractConfigItemFacade {
+ private static final Logger s_logger = Logger.getLogger(AbstractConfigItemFacade.class);
+
private final static Gson gson;
private static Hashtable<Class<? extends NetworkElementCommand>, AbstractConfigItemFacade> flyweight = new Hashtable<Class<? extends NetworkElementCommand>, AbstractConfigItemFacade>();
@@ -104,13 +108,26 @@ public abstract class AbstractConfigItemFacade {
return instance;
}
+ private static String appendUuidToJsonFiles(final String filename) {
+ String remoteFileName = new String(filename);
+ if (remoteFileName.endsWith("json")) {
+ remoteFileName += "." + UUID.randomUUID().toString();
+ }
+ return remoteFileName;
+ }
+
protected List<ConfigItem> generateConfigItems(final ConfigBase configuration) {
final List<ConfigItem> cfg = new LinkedList<>();
- final ConfigItem configFile = new FileConfigItem(VRScripts.CONFIG_PERSIST_LOCATION, destinationFile, gson.toJson(configuration));
+ final String remoteFilename = appendUuidToJsonFiles(destinationFile);
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Transformed filename: " + destinationFile + " to: " + remoteFilename);
+ }
+
+ final ConfigItem configFile = new FileConfigItem(VRScripts.CONFIG_PERSIST_LOCATION, remoteFilename, gson.toJson(configuration));
cfg.add(configFile);
- final ConfigItem updateCommand = new ScriptConfigItem(VRScripts.UPDATE_CONFIG, destinationFile);
+ final ConfigItem updateCommand = new ScriptConfigItem(VRScripts.UPDATE_CONFIG, remoteFilename);
cfg.add(updateCommand);
return cfg;
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 952fe9e..2e5d571 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -332,6 +332,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
if (details == null) {
details = parser.getLines();
}
+
+ s_logger.debug("Executing script in VR: " + script);
+
return new ExecutionResult(command.getExitValue() == 0, details);
}
@@ -340,6 +343,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
final File permKey = new File("/root/.ssh/id_rsa.cloud");
String error = null;
+ s_logger.debug("Creating file in VR, with ip: " + routerIp + ", file: " + filename);
+
try {
SshHelper.scpTo(routerIp, 3922, "root", permKey, null, path, content.getBytes(), filename, null);
} catch (final Exception e) {
diff --git a/systemvm/patches/debian/etc/rc.local b/systemvm/patches/debian/etc/rc.local
index bb4e251..895c120 100755
--- a/systemvm/patches/debian/etc/rc.local
+++ b/systemvm/patches/debian/etc/rc.local
@@ -67,12 +67,3 @@ then
python /opt/cloud/bin/baremetal-vr.py &
logger -t cloud "Started baremetal-vr service"
fi
-
-if [ "$TYPE" == "router" ] || [ "$TYPE" == "vpcrouter" ] || [ "$TYPE" == "dhcpsrvr" ]
-then
- if [ -x /opt/cloud/bin/update_config.py ]
- then
- /opt/cloud/bin/update_config.py cmd_line.json
- logger -t cloud "Updated config: cmd_line.json"
- fi
-fi
diff --git a/systemvm/patches/debian/opt/cloud/bin/configure.py b/systemvm/patches/debian/opt/cloud/bin/configure.py
index b8a3e02..3b39e6d 100755
--- a/systemvm/patches/debian/opt/cloud/bin/configure.py
+++ b/systemvm/patches/debian/opt/cloud/bin/configure.py
@@ -17,33 +17,29 @@
# specific language governing permissions and limitations
# under the License.
import sys
-import os
import base64
-from merge import DataBag
-from pprint import pprint
-import subprocess
+from collections import OrderedDict
+
import logging
import re
-import time
-import shutil
+
import os.path
import os
from fcntl import flock, LOCK_EX, LOCK_UN
-from cs.CsDatabag import CsDataBag, CsCmdLine
-import cs.CsHelper
+from cs.CsDatabag import CsDataBag
from cs.CsNetfilter import CsNetfilters
from cs.CsDhcp import CsDhcp
from cs.CsRedundant import *
from cs.CsFile import CsFile
-from cs.CsApp import CsApache, CsDnsmasq
from cs.CsMonitor import CsMonitor
from cs.CsLoadBalancer import CsLoadBalancer
from cs.CsConfig import CsConfig
from cs.CsProcess import CsProcess
from cs.CsStaticRoutes import CsStaticRoutes
+OCCURRENCES = 1
class CsPassword(CsDataBag):
@@ -668,16 +664,11 @@ class CsRemoteAccessVpn(CsDataBag):
continue
vpnconfig=self.dbag[public_ip]
- #Enable remote access vpn
+ # Enable remote access vpn
if vpnconfig['create']:
shutdownIpsec = False
logging.debug("Enabling remote access vpn on "+ public_ip)
- dev = CsHelper.get_device(public_ip)
- if dev == "":
- logging.error("Request for ipsec to %s not possible because ip is not configured", public_ip)
- continue
-
CsHelper.start_if_stopped("ipsec")
self.configure_l2tpIpsec(public_ip, self.dbag[public_ip])
logging.debug("Remote accessvpn data bag %s", self.dbag)
@@ -960,16 +951,49 @@ class CsForwardingRules(CsDataBag):
self.fw.append(["nat", "front", "-A POSTROUTING -s %s -d %s -j SNAT -o eth0 --to-source %s" % (self.getNetworkByIp(rule['internal_ip']),rule["internal_ip"], self.getGuestIp())])
+class IpTablesExecutor:
+
+ config = None
+
+ def __init__(self, config):
+ self.config = config
+
+ def process(self):
+ acls = CsAcl('networkacl', self.config)
+ acls.process()
+
+ acls = CsAcl('firewallrules', self.config)
+ acls.process()
+
+ fwd = CsForwardingRules("forwardingrules", self.config)
+ fwd.process()
+
+ vpns = CsSite2SiteVpn("site2sitevpn", self.config)
+ vpns.process()
+
+ rvpn = CsRemoteAccessVpn("remoteaccessvpn", self.config)
+ rvpn.process()
+
+ lb = CsLoadBalancer("loadbalancer", self.config)
+ lb.process()
+
+ logging.debug("Configuring iptables rules")
+ nf = CsNetfilters()
+ nf.compare(self.config.get_fw())
+
+ logging.debug("Configuring iptables rules done ...saving rules")
+
+ # Save iptables configuration - will be loaded on reboot by the iptables-restore that is configured on /etc/rc.local
+ CsHelper.save_iptables("iptables-save", "/etc/iptables/router_rules.v4")
+ CsHelper.save_iptables("ip6tables-save", "/etc/iptables/router_rules.v6")
+
def main(argv):
# The file we are currently processing, if it is "cmd_line.json" everything will be processed.
process_file = argv[1]
- # process_file can be None, if so assume cmd_line.json
if process_file is None:
- process_file = "cmd_line.json"
-
- # Track if changes need to be committed to NetFilter
- iptables_change = False
+ logging.debug("No file was received, do not go on processing the other actions. Just leave for now.")
+ return
# The "GLOBAL" Configuration object
config = CsConfig()
@@ -977,108 +1001,60 @@ def main(argv):
logging.basicConfig(filename=config.get_logger(),
level=config.get_level(),
format=config.get_format())
- try:
- # Load stored ip adresses from disk to CsConfig()
- config.set_address()
-
- logging.debug("Configuring ip addresses")
- config.address().compare()
- config.address().process()
-
- if process_file in ["cmd_line.json", "guest_network.json"]:
- logging.debug("Configuring Guest Network")
- iptables_change = True
-
- if process_file in ["cmd_line.json", "vm_password.json"]:
- logging.debug("Configuring vmpassword")
- password = CsPassword("vmpassword", config)
- password.process()
-
- if process_file in ["cmd_line.json", "vm_metadata.json"]:
- logging.debug("Configuring vmdata")
- metadata = CsVmMetadata('vmdata', config)
- metadata.process()
-
- if process_file in ["cmd_line.json", "network_acl.json"]:
- logging.debug("Configuring networkacl")
- iptables_change = True
-
- if process_file in ["cmd_line.json", "firewall_rules.json"]:
- logging.debug("Configuring firewall rules")
- iptables_change = True
-
- if process_file in ["cmd_line.json", "forwarding_rules.json", "staticnat_rules.json"]:
- logging.debug("Configuring PF rules")
- iptables_change = True
-
- if process_file in ["cmd_line.json", "site_2_site_vpn.json"]:
- logging.debug("Configuring s2s vpn")
- iptables_change = True
-
- if process_file in ["cmd_line.json", "remote_access_vpn.json"]:
- logging.debug("Configuring remote access vpn")
- iptables_change = True
-
- if process_file in ["cmd_line.json", "vpn_user_list.json"]:
- logging.debug("Configuring vpn users list")
- vpnuser = CsVpnUser("vpnuserlist", config)
- vpnuser.process()
-
- if process_file in ["cmd_line.json", "vm_dhcp_entry.json", "dhcp.json"]:
- logging.debug("Configuring dhcp entry")
- dhcp = CsDhcp("dhcpentry", config)
- dhcp.process()
-
- if process_file in ["cmd_line.json", "load_balancer.json"]:
- logging.debug("Configuring load balancer")
- iptables_change = True
-
- if process_file in ["cmd_line.json", "monitor_service.json"]:
- logging.debug("Configuring monitor service")
- mon = CsMonitor("monitorservice", config)
- mon.process()
-
- # If iptable rules have changed, apply them.
- if iptables_change:
- acls = CsAcl('networkacl', config)
- acls.process()
-
- acls = CsAcl('firewallrules', config)
- acls.flushAllowAllEgressRules()
- acls.process()
-
- fwd = CsForwardingRules("forwardingrules", config)
- fwd.process()
-
- vpns = CsSite2SiteVpn("site2sitevpn", config)
- vpns.process()
-
- rvpn = CsRemoteAccessVpn("remoteaccessvpn", config)
- rvpn.process()
-
- lb = CsLoadBalancer("loadbalancer", config)
- lb.process()
-
- logging.debug("Configuring iptables rules")
- nf = CsNetfilters()
- nf.compare(config.get_fw())
-
- logging.debug("Configuring iptables rules done ...saving rules")
-
- # Save iptables configuration - will be loaded on reboot by the iptables-restore that is configured on /etc/rc.local
- CsHelper.save_iptables("iptables-save", "/etc/iptables/router_rules.v4")
- CsHelper.save_iptables("ip6tables-save", "/etc/iptables/router_rules.v6")
-
- red = CsRedundant(config)
- red.set()
-
- if process_file in ["cmd_line.json", "static_routes.json"]:
- logging.debug("Configuring static routes")
- static_routes = CsStaticRoutes("staticroutes", config)
- static_routes.process()
- except Exception:
- logging.exception("Exception while configuring router")
- return 1
+ # Load stored ip adresses from disk to CsConfig()
+ config.set_address()
+
+ logging.debug("Configuring ip addresses")
+ config.address().compare()
+ config.address().process()
+
+ databag_map = OrderedDict([("guest_network.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("vm_password.json", {"process_iptables" : False, "executor" : CsPassword("vmpassword", config)}),
+ ("vm_metadata.json", {"process_iptables" : False, "executor" : CsVmMetadata('vmdata', config)}),
+ ("network_acl.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("firewall_rules.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("forwarding_rules.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("staticnat_rules.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("site_2_site_vpn.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("remote_access_vpn.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("vpn_user_list.json", {"process_iptables" : False, "executor" : CsVpnUser("vpnuserlist", config)}),
+ ("vm_dhcp_entry.json", {"process_iptables" : False, "executor" : CsDhcp("dhcpentry", config)}),
+ ("dhcp.json", {"process_iptables" : False, "executor" : CsDhcp("dhcpentry", config)}),
+ ("load_balancer.json", {"process_iptables" : True, "executor" : IpTablesExecutor(config)}),
+ ("monitor_service.json", {"process_iptables" : False, "executor" : CsMonitor("monitorservice", config)}),
+ ("static_routes.json", {"process_iptables" : False, "executor" : CsStaticRoutes("staticroutes", config)})
+ ])
+
+ if process_file.count("cmd_line.json") == OCCURRENCES:
+ logging.debug("cmd_line.json changed. All other files will be processed as well.")
+
+ while databag_map:
+ item = databag_map.popitem(last = False)
+ item_name = item[0]
+ item_dict = item[1]
+ if not item_dict["process_iptables"]:
+ executor = item_dict["executor"]
+ executor.process()
+
+ iptables_executor = IpTablesExecutor(config)
+ iptables_executor.process()
+ else:
+ while databag_map:
+ item = databag_map.popitem(last = False)
+ item_name = item[0]
+ item_dict = item[1]
+ if process_file.count(item_name) == OCCURRENCES:
+ executor = item_dict["executor"]
+ executor.process()
+
+ if item_dict["process_iptables"]:
+ iptables_executor = IpTablesExecutor(config)
+ iptables_executor.process()
+
+ break
+
+ red = CsRedundant(config)
+ red.set()
if __name__ == "__main__":
main(sys.argv)
diff --git a/systemvm/patches/debian/opt/cloud/bin/merge.py b/systemvm/patches/debian/opt/cloud/bin/merge.py
index 1c9adf2..ef20d0b 100755
--- a/systemvm/patches/debian/opt/cloud/bin/merge.py
+++ b/systemvm/patches/debian/opt/cloud/bin/merge.py
@@ -18,8 +18,10 @@
import json
import os
-import time
+import uuid
import logging
+import gzip
+import shutil
import cs_ip
import cs_guestnetwork
import cs_cmdline
@@ -36,8 +38,6 @@ import cs_remoteaccessvpn
import cs_vpnusers
import cs_staticroutes
-from pprint import pprint
-
class DataBag:
@@ -282,22 +282,26 @@ class QueueFile:
if data is not None:
self.data = data
self.type = self.data["type"]
- proc = updateDataBag(self)
+ updateDataBag(self)
return
- fn = self.configCache + '/' + self.fileName
+ filename = '{cache_location}/{json_file}'.format(cache_location = self.configCache, json_file = self.fileName)
try:
- handle = open(fn)
- except IOError:
- logging.error("Could not open %s", fn)
+ handle = open(filename)
+ except IOError as exception:
+ error_message = ("Exception occurred with the following exception error '{error}'. Could not open '{file}'. "
+ "It seems that the file has already been moved.".format(error = exception, file = filename))
+ logging.error(error_message)
else:
+ logging.info("Continuing with the processing of file '{file}'".format(file = filename))
+
self.data = json.load(handle)
self.type = self.data["type"]
handle.close()
if self.keep:
- self.__moveFile(fn, self.configCache + "/processed")
+ self.__moveFile(filename, self.configCache + "/processed")
else:
- os.remove(fn)
- proc = updateDataBag(self)
+ os.remove(filename)
+ updateDataBag(self)
def setFile(self, name):
self.fileName = name
@@ -314,8 +318,15 @@ class QueueFile:
def __moveFile(self, origPath, path):
if not os.path.exists(path):
os.makedirs(path)
- timestamp = str(int(round(time.time())))
- os.rename(origPath, path + "/" + self.fileName + "." + timestamp)
+ originalName = os.path.basename(origPath)
+ if originalName.count(".") == 1:
+ originalName += "." + str(uuid.uuid4())
+ zipped_file_name = path + "/" + originalName + ".gz"
+ with open(origPath, 'rb') as f_in, gzip.open(zipped_file_name, 'wb') as f_out:
+ shutil.copyfileobj(f_in, f_out)
+ os.remove(origPath)
+
+ logging.debug("Processed file written to %s", zipped_file_name)
class PrivateGatewayHack:
diff --git a/systemvm/patches/debian/opt/cloud/bin/update_config.py b/systemvm/patches/debian/opt/cloud/bin/update_config.py
index ab08e03..e36980a 100755
--- a/systemvm/patches/debian/opt/cloud/bin/update_config.py
+++ b/systemvm/patches/debian/opt/cloud/bin/update_config.py
@@ -26,6 +26,8 @@ import os.path
import configure
import json
+OCCURRENCES = 1
+
logging.basicConfig(filename='/var/log/cloud.log', level=logging.INFO, format='%(asctime)s %(filename)s %(funcName)s:%(lineno)d %(message)s')
# first commandline argument should be the file to process
@@ -39,6 +41,14 @@ jsonCmdConfigPath = jsonPath % sys.argv[1]
currentGuestNetConfig = "/etc/cloudstack/guestnetwork.json"
+# If the command line json file is unprocessed process it
+# This is important or, the control interfaces will get deleted!
+if os.path.isfile(jsonPath % "cmd_line.json"):
+ qf = QueueFile()
+ qf.setFile("cmd_line.json")
+ qf.load(None)
+
+
def finish_config():
# Converge
returncode = configure.main(sys.argv)
@@ -111,19 +121,13 @@ def is_guestnet_configured(guestnet_dict, keys):
return exists
-if not (os.path.isfile(jsonCmdConfigPath) and os.access(jsonCmdConfigPath, os.R_OK)):
+filename = jsonCmdConfigPath
+if not (os.path.isfile(filename) and os.access(filename, os.R_OK)):
print "[ERROR] update_config.py :: You are telling me to process %s, but i can't access it" % jsonCmdConfigPath
sys.exit(1)
-# If the command line json file is unprocessed process it
-# This is important or, the control interfaces will get deleted!
-if os.path.isfile(jsonPath % "cmd_line.json"):
- qf = QueueFile()
- qf.setFile("cmd_line.json")
- qf.load(None)
-
# If the guest network is already configured and have the same IP, do not try to configure it again otherwise it will break
-if sys.argv[1] == "guest_network.json":
+if sys.argv[1] and sys.argv[1].count("guest_network.json") == OCCURRENCES:
if os.path.isfile(currentGuestNetConfig):
file = open(currentGuestNetConfig)
guestnet_dict = json.load(file)
--
To stop receiving notification emails like this one, please contact
"commits@cloudstack.apache.org" <co...@cloudstack.apache.org>.