1""" 2 Server Density 3 www.serverdensity.com 4 ---- 5 Server monitoring agent for Linux, FreeBSD and Mac OS X 6 7 Licensed under Simplified BSD License (see LICENSE) 8""" 9import httplib 10import os 11import platform 12import shutil 13import socket 14import subprocess 15import sys 16import time 17import urllib 18import urllib2 19 20try: 21 from hashlib import md5 22except ImportError: # Python < 2.5 23 from md5 import new as md5 24 25# 26# Why are you using this? 27# 28print 'Note: This script is for automating deployments and is not the normal way to install the SD agent. See http://www.serverdensity.com/docs/agent/installation/' 29print 'Continuing in 4 seconds...' 30time.sleep(4) 31 32# 33# Argument checks 34# 35 36if len(sys.argv) < 5: 37 print 'Usage: python sd-deploy.py [API URL] [SD URL] [username] [password] [[init]]' 38 sys.exit(2) 39 40# 41# Get server details 42# 43 44# IP 45try: 46 serverIp = socket.gethostbyname(socket.gethostname()) 47 48except socket.error, e: 49 print 'Unable to get server IP: ' + str(e) 50 sys.exit(2) 51 52# Hostname 53try: 54 serverHostname = hostname = socket.getfqdn() 55 56except socket.error, e: 57 print 'Unable to get server hostname: ' + str(e) 58 sys.exit(2) 59 60# 61# Get latest agent version 62# 63 64print '1/4: Downloading latest agent version' 65 66# Request details 67try: 68 requestAgent = urllib2.urlopen('http://www.serverdensity.com/agentupdate/') 69 responseAgent = requestAgent.read() 70 71except urllib2.HTTPError, e: 72 print 'Unable to get latest version info - HTTPError = ' + str(e) 73 sys.exit(2) 74 75except urllib2.URLError, e: 76 print 'Unable to get latest version info - URLError = ' + str(e) 77 sys.exit(2) 78 79except httplib.HTTPException, e: 80 print 'Unable to get latest version info - HTTPException' 81 sys.exit(2) 82 83except Exception: 84 import traceback 85 print 'Unable to get latest version info - Exception = ' + traceback.format_exc() 86 sys.exit(2) 87 88 89# 90# Define downloader function 91# 92def downloadFile(agentFile, recursed=False): 93 print 'Downloading ' + agentFile['name'] 94 downloadedFile = urllib.urlretrieve('http://www.serverdensity.com/downloads/sd-agent/' + agentFile['name']) 95 96 # Do md5 check to make sure the file downloaded properly 97 checksum = md5() 98 f = open(downloadedFile[0], 'rb') 99 100 # Although the files are small, we can't guarantee the available memory nor that there 101 # won't be large files in the future, so read the file in small parts (1kb at time) 102 while True: 103 part = f.read(1024) 104 if not part: 105 break # end of file 106 checksum.update(part) 107 108 f.close() 109 110 # Do we have a match? 111 if checksum.hexdigest() == agentFile['md5']: 112 return downloadedFile[0] 113 114 else: 115 # Try once more 116 if not recursed: 117 downloadFile(agentFile, True) 118 119 else: 120 print agentFile['name'] + ' did not match its checksum - it is corrupted. This may be caused by network issues so please try again in a moment.' 121 sys.exit(2) 122 123# 124# Install the agent files 125# 126 127# We need to return the data using JSON. As of Python 2.6+, there is a core JSON 128# module. We have a 2.4/2.5 compatible lib included with the agent but if we're 129# on 2.6 or above, we should use the core module which will be faster 130pythonVersion = platform.python_version_tuple() 131 132# Decode the JSON 133if int(pythonVersion[1]) >= 6: # Don't bother checking major version since we only support v2 anyway 134 import json 135 136 try: 137 updateInfo = json.loads(responseAgent) 138 except Exception, e: 139 print 'Unable to get latest version info. Try again later.' 140 sys.exit(2) 141 142else: 143 import minjson 144 145 try: 146 updateInfo = minjson.safeRead(responseAgent) 147 except Exception, e: 148 print 'Unable to get latest version info. Try again later.' 149 sys.exit(2) 150 151# Loop through the new files and call the download function 152for agentFile in updateInfo['files']: 153 agentFile['tempFile'] = downloadFile(agentFile) 154 155# If we got to here then everything worked out fine. However, all the files are 156# still in temporary locations so we need to move them. 157# 158# Make sure doesn't exist already. 159# Usage of shutil prevents [Errno 18] Invalid cross-device link (case 26878) - 160# http://mail.python.org/pipermail/python-list/2005-February/308026.html 161if os.path.exists('sd-agent/'): 162 shutil.rmtree('sd-agent/') 163 164os.mkdir('sd-agent') 165 166for agentFile in updateInfo['files']: 167 print 'Installing ' + agentFile['name'] 168 169 if agentFile['name'] != 'config.cfg': 170 shutil.move(agentFile['tempFile'], 'sd-agent/' + agentFile['name']) 171 172print 'Agent files downloaded' 173 174# 175# Call API to add new server 176# 177 178print '2/4: Adding new server' 179 180# Build API payload 181timestamp = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime()) 182 183postData = urllib.urlencode({'name': serverHostname, 'ip': serverIp, 'notes': 'Added by sd-deploy: ' + timestamp}) 184 185# Send request 186try: 187 # Password manager 188 mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 189 mgr.add_password(None, sys.argv[1] + '/1.0/', sys.argv[3], sys.argv[4]) 190 opener = urllib2.build_opener(urllib2.HTTPBasicAuthHandler(mgr), urllib2.HTTPDigestAuthHandler(mgr)) 191 192 urllib2.install_opener(opener) 193 194 # Build the request handler 195 requestAdd = urllib2.Request(sys.argv[1] + '/1.0/?account=' + sys.argv[2] + '&c=servers/add', postData, {'User-Agent': 'Server Density Deploy'}) 196 197 # Do the request, log any errors 198 responseAdd = urllib2.urlopen(requestAdd) 199 200 readAdd = responseAdd.read() 201 202except urllib2.HTTPError, e: 203 print 'HTTPError = ' + str(e) 204 205 if os.path.exists('sd-agent/'): 206 shutil.rmtree('sd-agent/') 207 208except urllib2.URLError, e: 209 print 'URLError = ' + str(e) 210 211 if os.path.exists('sd-agent/'): 212 shutil.rmtree('sd-agent/') 213 214except httplib.HTTPException, e: # Added for case #26701 215 print 'HTTPException' + str(e) 216 217 if os.path.exists('sd-agent/'): 218 shutil.rmtree('sd-agent/') 219 220except Exception, e: 221 import traceback 222 print 'Exception = ' + traceback.format_exc() 223 224 if os.path.exists('sd-agent/'): 225 shutil.rmtree('sd-agent/') 226 227# Decode the JSON 228if int(pythonVersion[1]) >= 6: # Don't bother checking major version since we only support v2 anyway 229 import json 230 231 try: 232 serverInfo = json.loads(readAdd) 233 except Exception, e: 234 print 'Unable to add server.' 235 236 if os.path.exists('sd-agent/'): 237 shutil.rmtree('sd-agent/') 238 239 sys.exit(2) 240 241else: 242 import minjson 243 244 try: 245 serverInfo = minjson.safeRead(readAdd) 246 except Exception, e: 247 print 'Unable to add server.' 248 249 if os.path.exists('sd-agent/'): 250 shutil.rmtree('sd-agent/') 251 252 sys.exit(2) 253 254print 'Server added - ID: ' + str(serverInfo['data']['serverId']) 255 256# 257# Write config file 258# 259 260print '3/4: Writing config file' 261 262configCfg = '[Main]\nsd_url: http://' + sys.argv[2] + '\nagent_key: ' + serverInfo['data']['agentKey'] + '\napache_status_url: http://www.example.com/server-status/?auto' 263 264try: 265 f = open('sd-agent/config.cfg', 'w') 266 f.write(configCfg) 267 f.close() 268 269except Exception: 270 import traceback 271 print 'Exception = ' + traceback.format_exc() 272 273 if os.path.exists('sd-agent/'): 274 shutil.rmtree('sd-agent/') 275 276print 'Config file written' 277 278# 279# Install init.d 280# 281 282if len(sys.argv) == 6: 283 284 print '4/4: Installing init.d script' 285 286 shutil.copy('sd-agent/sd-agent.init', '/etc/init.d/sd-agent') 287 288 print 'Setting permissions' 289 290 df = subprocess.Popen(['chmod', '0755', '/etc/init.d/sd-agent'], stdout=subprocess.PIPE).communicate()[0] 291 292 print 'chkconfig' 293 294 df = subprocess.Popen(['chkconfig', '--add', 'sd-agent'], stdout=subprocess.PIPE).communicate()[0] 295 296 print 'Setting paths' 297 298 path = os.path.realpath(__file__) 299 path = os.path.dirname(path) 300 301 df = subprocess.Popen(['ln', '-s', path + '/sd-agent/', '/usr/bin/sd-agent'], stdout=subprocess.PIPE).communicate()[0] 302 303 print 'Install completed' 304 305 print 'Launch: /etc/init.d/sd-agent start' 306 307else: 308 309 print '4/4: Not installing init.d script' 310 print 'Install completed' 311 312 path = os.path.realpath(__file__) 313 path = os.path.dirname(path) 314 315 print 'Launch: python ' + path + '/sd-agent/agent.py start' 316