| # 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. | |
| import logging | |
| import os.path | |
| from os import listdir | |
| import re | |
| from cs.CsDatabag import CsDataBag | |
| from .CsProcess import CsProcess | |
| from .CsFile import CsFile | |
| from . import CsHelper | |
| HAPROXY_CONF_T = "/etc/haproxy/haproxy.cfg.new" | |
| HAPROXY_CONF_P = "/etc/haproxy/haproxy.cfg" | |
| SSL_CERTS_DIR = "/etc/cloudstack/ssl/" | |
| class CsLoadBalancer(CsDataBag): | |
| """ Manage Load Balancer entries """ | |
| def process(self): | |
| if "config" not in list(self.dbag.keys()): | |
| return | |
| if 'configuration' not in list(self.dbag['config'][0].keys()): | |
| return | |
| if 'ssl_certs' in list(self.dbag['config'][0].keys()): | |
| self._create_pem_for_sslcert(self.dbag['config'][0]['ssl_certs']) | |
| config = self.dbag['config'][0]['configuration'] | |
| file1 = CsFile(HAPROXY_CONF_T) | |
| file1.empty() | |
| for x in config: | |
| [file1.append(w, -1) for w in x.split('\n')] | |
| file1.commit() | |
| file2 = CsFile(HAPROXY_CONF_P) | |
| if not file2.compare(file1): | |
| # Verify new haproxy config before haproxy restart/reload | |
| haproxy_err = self._verify_haproxy_config(HAPROXY_CONF_T) | |
| if haproxy_err: | |
| raise Exception("haproxy config is invalid with error \n%s" % haproxy_err) | |
| CsHelper.copy(HAPROXY_CONF_T, HAPROXY_CONF_P) | |
| proc = CsProcess(['/run/haproxy.pid']) | |
| if not proc.find(): | |
| logging.debug("CsLoadBalancer:: will restart HAproxy!") | |
| CsHelper.service("haproxy", "restart") | |
| else: | |
| logging.debug("CsLoadBalancer:: will reload HAproxy!") | |
| CsHelper.service("haproxy", "reload") | |
| add_rules = self.dbag['config'][0]['add_rules'] | |
| remove_rules = self.dbag['config'][0]['remove_rules'] | |
| stat_rules = self.dbag['config'][0]['stat_rules'] | |
| self._configure_firewall(add_rules, remove_rules, stat_rules) | |
| def _configure_firewall(self, add_rules, remove_rules, stat_rules): | |
| firewall = self.config.get_fw() | |
| logging.debug("CsLoadBalancer:: configuring firewall. Add rules ==> %s" % add_rules) | |
| logging.debug("CsLoadBalancer:: configuring firewall. Remove rules ==> %s" % remove_rules) | |
| logging.debug("CsLoadBalancer:: configuring firewall. Stat rules ==> %s" % stat_rules) | |
| for rules in add_rules: | |
| path = rules.split(':') | |
| ip = path[0] | |
| port = path[1] | |
| firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)]) | |
| for rules in remove_rules: | |
| path = rules.split(':') | |
| ip = path[0] | |
| port = path[1] | |
| firewall.append(["filter", "", "-D INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)]) | |
| for rules in stat_rules: | |
| path = rules.split(':') | |
| ip = path[0] | |
| port = path[1] | |
| firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)]) | |
| def _create_pem_for_sslcert(self, ssl_certs): | |
| logging.debug("CsLoadBalancer:: creating new pem files in %s and cleaning up it" % SSL_CERTS_DIR) | |
| if not os.path.exists(SSL_CERTS_DIR): | |
| CsHelper.execute("mkdir -p %s" % SSL_CERTS_DIR) | |
| cert_names = [] | |
| for cert in ssl_certs: | |
| cert_names.append(cert['name'] + ".pem") | |
| file = CsFile("%s/%s.pem" % (SSL_CERTS_DIR, cert['name'])) | |
| file.empty() | |
| file.add("%s\n" % cert['cert'].replace("\r\n", "\n")) | |
| if 'chain' in cert.keys(): | |
| file.add("%s\n" % cert['chain'].replace("\r\n", "\n")) | |
| file.add("%s\n" % cert['key'].replace("\r\n", "\n")) | |
| file.commit() | |
| for f in listdir(SSL_CERTS_DIR): | |
| if f not in cert_names: | |
| CsHelper.execute("rm -rf %s/%s" % (SSL_CERTS_DIR, f)) | |
| def _verify_haproxy_config(self, config): | |
| ret = CsHelper.execute2("haproxy -c -f %s" % config) | |
| if ret.returncode: | |
| stdout, stderr = ret.communicate() | |
| logging.error("haproxy config is invalid with error: %s" % stderr) | |
| return stderr | |
| return "" |