mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-11-04 00:02:37 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#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.
 | 
						|
 | 
						|
__author__ = 'frank'
 | 
						|
 | 
						|
import subprocess
 | 
						|
import urllib
 | 
						|
import hmac
 | 
						|
import hashlib
 | 
						|
import base64
 | 
						|
import traceback
 | 
						|
import logging
 | 
						|
 | 
						|
from flask import Flask
 | 
						|
 | 
						|
app = Flask(__name__)
 | 
						|
 | 
						|
logger = logging.getLogger('baremetal-vr')
 | 
						|
hdlr = logging.FileHandler('/var/log/baremetal-vr.log')
 | 
						|
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
 | 
						|
hdlr.setFormatter(formatter)
 | 
						|
logger.addHandler(hdlr)
 | 
						|
logger.setLevel(logging.WARNING)
 | 
						|
 | 
						|
class ShellCmd(object):
 | 
						|
    '''
 | 
						|
    classdocs
 | 
						|
    '''
 | 
						|
    def __init__(self, cmd, workdir=None, pipe=True):
 | 
						|
        '''
 | 
						|
        Constructor
 | 
						|
        '''
 | 
						|
        self.cmd = cmd
 | 
						|
        if pipe:
 | 
						|
            self.process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/sh', cwd=workdir)
 | 
						|
        else:
 | 
						|
            self.process = subprocess.Popen(cmd, shell=True, executable='/bin/sh', cwd=workdir)
 | 
						|
 | 
						|
        self.stdout = None
 | 
						|
        self.stderr = None
 | 
						|
        self.return_code = None
 | 
						|
 | 
						|
    def __call__(self, is_exception=True):
 | 
						|
        (self.stdout, self.stderr) = self.process.communicate()
 | 
						|
        if is_exception and self.process.returncode != 0:
 | 
						|
            err = []
 | 
						|
            err.append('failed to execute shell command: %s' % self.cmd)
 | 
						|
            err.append('return code: %s' % self.process.returncode)
 | 
						|
            err.append('stdout: %s' % self.stdout)
 | 
						|
            err.append('stderr: %s' % self.stderr)
 | 
						|
            raise Exception('\n'.join(err))
 | 
						|
 | 
						|
        self.return_code = self.process.returncode
 | 
						|
        return self.stdout
 | 
						|
 | 
						|
def shell(cmd):
 | 
						|
    return ShellCmd(cmd)()
 | 
						|
 | 
						|
 | 
						|
class Server(object):
 | 
						|
    CMDLINE = '/var/cache/cloud/cmdline'
 | 
						|
    def __init__(self):
 | 
						|
        self.apikey = None
 | 
						|
        self.secretkey = None
 | 
						|
        self.mgmtIp = None
 | 
						|
        self.mgmtPort = None
 | 
						|
 | 
						|
    def _get_credentials(self):
 | 
						|
        if not self.apikey or not self.secretkey:
 | 
						|
            with open(self.CMDLINE, 'r') as fd:
 | 
						|
                cmdline = fd.read()
 | 
						|
                for p in cmdline.split():
 | 
						|
                    if 'baremetalnotificationsecuritykey' in p:
 | 
						|
                        self.secretkey = p.split("=")[1]
 | 
						|
                    if 'baremetalnotificationapikey' in p:
 | 
						|
                        self.apikey = p.split("=")[1]
 | 
						|
 | 
						|
        if not self.apikey:
 | 
						|
            raise Exception('cannot find baremetalnotificationapikey in %s' % Server.CMDLINE)
 | 
						|
        if not self.secretkey:
 | 
						|
            raise Exception('cannot find baremetalnotificationsecuritykey in %s' % Server.CMDLINE)
 | 
						|
 | 
						|
        return self.apikey, self.secretkey
 | 
						|
 | 
						|
    def _get_mgmt_ip(self):
 | 
						|
        if not self.mgmtIp:
 | 
						|
            with open(self.CMDLINE, 'r') as fd:
 | 
						|
                cmdline = fd.read()
 | 
						|
                for p in cmdline.split():
 | 
						|
                    if 'host' in p:
 | 
						|
                        self.mgmtIp = p.split("=")[1]
 | 
						|
                        break
 | 
						|
 | 
						|
        if not self.mgmtIp:
 | 
						|
            raise Exception('cannot find host in %s' % Server.CMDLINE)
 | 
						|
 | 
						|
        return self.mgmtIp
 | 
						|
 | 
						|
    def _get_mgmt_port(self):
 | 
						|
        if not self.mgmtPort:
 | 
						|
            with open(self.CMDLINE, 'r') as fd:
 | 
						|
                cmdline = fd.read()
 | 
						|
                for p in cmdline.split():
 | 
						|
                    if 'port' in p:
 | 
						|
                        self.mgmtPort = p.split("=")[1]
 | 
						|
                        break
 | 
						|
 | 
						|
        if not self.mgmtIp:
 | 
						|
            raise Exception('cannot find port in %s' % Server.CMDLINE)
 | 
						|
 | 
						|
        return self.mgmtPort
 | 
						|
 | 
						|
    def _make_sign(self, mac):
 | 
						|
        apikey, secretkey = self._get_credentials()
 | 
						|
        reqs = {
 | 
						|
            "apiKey": apikey,
 | 
						|
            "command": 'notifyBaremetalProvisionDone',
 | 
						|
            "mac": mac
 | 
						|
        }
 | 
						|
 | 
						|
        request = zip(reqs.keys(), reqs.values())
 | 
						|
        request.sort(key=lambda x: str.lower(x[0]))
 | 
						|
        hashStr = "&".join(["=".join([str.lower(r[0]), str.lower(urllib.quote_plus(str(r[1]))).replace("+", "%20").replace('=', '%3d')]) for r in request])
 | 
						|
        sig = urllib.quote_plus(base64.encodestring(hmac.new(secretkey, hashStr, hashlib.sha1).digest()).strip())
 | 
						|
        return sig
 | 
						|
 | 
						|
    def notify_provisioning_done(self, mac):
 | 
						|
        sig = self._make_sign(mac)
 | 
						|
        cmd = 'http://%s:%s/client/api?command=notifyBaremetalProvisionDone&mac=%s&apiKey=%s&signature=%s' % (self._get_mgmt_ip(), self._get_mgmt_port(), mac, self.apikey, sig)
 | 
						|
        shell("curl -X GET '%s'" % cmd)
 | 
						|
        return ''
 | 
						|
 | 
						|
server = None
 | 
						|
 | 
						|
@app.route('/baremetal/provisiondone/<mac>', methods=['GET'])
 | 
						|
def notify_provisioning_done(mac):
 | 
						|
    try:
 | 
						|
        return server.notify_provisioning_done(mac)
 | 
						|
    except:
 | 
						|
        logger.warn(traceback.format_exc())
 | 
						|
        return ''
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    global server
 | 
						|
    server = Server()
 | 
						|
    shell("iptables-save | grep -- '-A INPUT -i eth0 -p tcp -m tcp --dport 10086 -j ACCEPT' > /dev/null || iptables -I INPUT -i eth0 -p tcp -m tcp --dport 10086 -j ACCEPT")
 | 
						|
    app.run(host='0.0.0.0', port=10086, debug=True)
 |