#!/usr/bin/python # -*- coding: iso-8859-15 -*- ### OPEN SOURCE LICENSE - GNU AFFERO PUBLIC LICENSE Version 3.0 ####### # # Docker_is.py - python FullAuto Instruction Set using FullAuto API. # Copyright © 2016-2017 Brian M. Kelly # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License # as published by the Free Software Foundation, either version 3 of # the License, or any later version. # # This program is distributed in the hope that it will be useful, # but **WITHOUT ANY WARRANTY**; without even the implied warranty # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public # License along with this program. If not, see: # . # ####################################################################### from urllib.parse import urlencode import httplib2 import argparse import re import sys import getpass import os import os.path import json import socket import time try: # For c speedups from simplejson import loads, dumps except ImportError: from json import loads, dumps parser = argparse.ArgumentParser(description= 'Python Docker ISet using FullAuto API.') parser.add_argument('clientid') parser.add_argument('pem_file',nargs='?',default='fullauto.pem') parser.add_argument('domain',nargs='?',default='fullautosoftware.net') args=parser.parse_args() client_id = args.clientid; # https://web.archive.org/web/20160316113959/http://mancoosi.org/~abate/upload-file-using-httplib def upload(url,filename,bearer): def encode (file_path, fields=[]): BOUNDARY = '----------bundary------' CRLF = '\r\n' body = [] # Add the metadata about the upload first for key, value in fields: body.extend( ['--' + BOUNDARY, 'Content-Disposition: form-data; name="%s"' % key, '', value, ]) # Now add the file itself file_name = os.path.basename(file_path) f = open(file_path) file_content = f.read() f.close() body.extend( ['--' + BOUNDARY, 'Content-Disposition: form-data; name="file"; filename="%s"' % file_name, # The upload server determines the mime-type, no need to set it. 'Content-Type: application/octet-stream', '', file_content, ]) # Finalize the form body body.extend(['--' + BOUNDARY + '--', '']) # https://arstechnica.com/civis/viewtopic.php?t=202651 return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body) if os.path.exists(filename): print ("UPLOADING: "+filename) content_type, body = encode(filename) headers = { 'Content-Type': content_type,'Authorization': bearer } httpx = httplib2.Http(disable_ssl_certificate_validation=True) print (body) output=httpx.request(url,'POST', body, headers) print (output) print ("\n Waiting for 3 seconds . . .\n") time.sleep( 3 ) pem_file_path=''; from os.path import expanduser home = expanduser("~") cwd = os.getcwd() username = getpass.getuser() if os.path.isfile(args.pem_file) and os.access(args.pem_file, os.R_OK): print ("CWD="+cwd) pem_file_path=cwd+'/'+args.pem_file os.chmod(pem_file_path,0o777) print (pem_file_path+" exists and is readable") elif os.path.isfile(home+'/'+args.pem_file) and \ os.access(home+'/'+args.pem_file, os.R_OK): pem_file_path=home+'/'+args.pem_file os.chmod(pem_file_path,0o777) print (pem_file_path+" exists and is readable") elif os.path.isfile('/cygdrive/c/Users/'+username+'/Desktop/'+args.pem_file) \ and os.access('/cygdrive/c/Users/'+username+'/Desktop/'+args.pem_file, \ os.R_OK): pem_file_path='/cygdrive/c/Users/'+username+'/Desktop/'+args.pem_file os.chmod(pem_file_path,0o777) print (pem_file_path+"\nexists and is readable") else: print (args.pem_file+" is missing or is not readable") sys.exit() with open(pem_file_path) as f: pemfile = f.read() print (pemfile) http = httplib2.Http(disable_ssl_certificate_validation=True) http.follow_redirects = False url = "https://"+args.domain+"/request?client_id=" + client_id \ + "&response_type=code&redirect_uri=/cmd" print ("URL="+url) headerz, content = http.request(url, "GET") print (content) code = re.search('code=(\d+)',content.decode('utf-8')) code = code.group(1) url = "https://"+args.domain+"//token?grant_type=authorization_code&client_id=" \ + client_id + "&redirect_uri=/cmd&code=" + code headerz, content = http.request(url, "GET") accesstoken = re.search('access_token":(\d+)',content.decode('utf-8')) accesstoken = accesstoken.group(1); refreshtoken = re.search('refresh_token":(\d+)',content.decode('utf-8')) refreshtoken = refreshtoken.group(1); credentials_file = 'credentials.csv' if os.path.isfile(credentials_file) and os.access(credentials_file, os.R_OK): cred_file_path=cwd+'/'+credentials_file os.chmod(cred_file_path,0o777) print (cred_file_path+" exists and is readable") elif os.path.isfile(home+'/'+credentials_file) and \ os.access(home+'/'+credentials_file, os.R_OK): cred_file_path=home+'/'+credentials_file os.chmod(cred_file_path,0o777) print (cred_file_path+" exists and is readable") elif os.path.isfile('/cygdrive/c/Users/'+username+'/Desktop/'+ \ credentials_file) and os.access('/cygdrive/c/Users/'+username+ \ '/Desktop/'+credentials_file, os.R_OK): cred_file_path='/cygdrive/c/Users/'+username+'/Desktop/'+credentials_file os.chmod(cred_file_path,0o777) print (cred_file_path+"\nexists and is readable") else: print (credentials_file+" is missing or is not readable") sys.exit() bearer = "Bearer "+accesstoken url = 'https://'+args.domain+'/cmd' upload(url,cred_file_path,bearer) #sys.exit() with open("/tmp/"+credentials_file) as f: for line in f: items=line.split(','); #data = {'cmd': [['aws_configure',items[1],items[2]], data = {'cmd': [['cmd','hostname'], ['cwd','/bin'], ['cmd_raw','export HELLO=hello'], ['cmd','echo $HELLO'], ['cmd','pwd'], ['cmd','aws ec2 describe-instances']]} headers = {'Content-Type': 'application/json','Authorization': bearer } url = 'https://'+args.domain+'/cmd' headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) result = json.loads(result[5][0]) myip=([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] \ if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), \ s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, \ socket.SOCK_DGRAM)]][0][1]]) if l][0][0]) for inst in result['Reservations']: print (inst) for elem in inst['Instances']: print (elem) if elem['State']['Name'] == 'terminated': print ("GOT CONTINUE") continue if myip == elem['PrivateIpAddress']: print (elem['SecurityGroups'][0]['GroupId']) print (elem['PrivateIpAddress']) print (elem['State']['Name']) print (elem['SubnetId']) break else: continue break print ("\n Waiting for 3 seconds . . .\n") time.sleep( 3 ) gid = elem['SecurityGroups'][0]['GroupId'] sid = elem['SubnetId'] headers = {'Content-Type': 'application/json','Authorization': bearer } dsg = 'aws ec2 describe-security-groups' data = {'cmd':[['cmd',dsg]]}; headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) result = json.loads(result[0][0]) print (result) cidr='' dockergid='' for inst in result['SecurityGroups']: print (inst) dockergid = inst['GroupId'] try: cidr = inst['IpPermissions'][0]['IpRanges'][0]['CidrIp'] except IndexError: cidr = '' if gid == inst['GroupId']: break new_sg = 'aws ec2 create-security-group --group-name ' + \ 'DockerSecurityGroup --description ' + \ '"Docker.com Security Group" 2>&1'; ingress = 'aws ec2 authorize-security-group-ingress ' + \ '--group-name DockerSecurityGroup --protocol tcp ' + \ '--port 22 --cidr ' + cidr + ' 2>&1' print (ingress) print ("\n Waiting for 3 seconds . . .\n") time.sleep( 3 ) upload(url,pem_file_path,bearer) print (" Done With Upload . . .\n") #sys.exit() time.sleep( 1 ) data = {'cmd': [['cmd','echo $HOME'], ['cmd','echo $USER'], ['cmd','echo $HOSTNAME'], ['cmd','mkdir -pv $HOME/FullAutoAPI']]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) homedir=result[0][0] remuser=result[1][0] hostnam=result[2][0] lochost=socket.gethostname() if hostnam == lochost: remuser=username homedir=home time.sleep( 1 ) mvpem=args.pem_file if re.search(' ',args.pem_file): mvpem="'"+mvpem+"'" mvcre=credentials_file if re.search(' ',args.pem_file): mvcre="'"+mvcre+"'" data = {'cmd': [['cmd','sudo mv -vf /tmp/'+mvpem+ ' '+homedir+'/FullAutoAPI'], ['cmd','sudo mv -vf /tmp/'+mvcre+ ' '+homedir+'/FullAutoAPI'], ['cwd',homedir+'/FullAutoAPI'], ['cmd','chmod -v 400 '+mvpem], ['cmd',new_sg], ['cmd',ingress]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) from pprint import pprint sec_group_id='' if re.search('already exists for VPC',result[4][0]): get_sec='aws ec2 describe-security-groups --group-names DockerSecurityGroup' data = {'cmd': [['cmd',get_sec]]} time.sleep( 1 ) headerz, content = http.request(url, "POST", body=dumps(data), \ headers=headers) result = json.loads(content) result = json.loads(result['result']) result = json.loads(result[0][0]) sec_group_id = result['SecurityGroups'][0]['GroupId'] else: result=json.loads(result[4][0]) sec_group_id=result['GroupId'] time.sleep( 1 ) print (" Continuing . . .\n") #sys.exit() region = "sudo wget -qO- http://169.254.169.254/latest/dynamic/instance-identity/document|grep region" data = {'cmd': [['cmd',region]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) region=re.search(': "(.+)"',result[0][0]).group(1) time.sleep(1) get_inst = 'aws ec2 describe-images --owners self amazon --filters "Name=root-device-type,Values=ebs" "Name=virtualization-type,Values=hvm" "Name=architecture,Values=x86_64" "Name=block-device-mapping.volume-size,Values=8" "Name=block-device-mapping.volume-type,Values=gp2" "Name=state,Values=available" --region='+region data = {'cmd': [['cmd',get_inst]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) result = json.loads(result[0][0]) imagid = result['Images'][0]['ImageId'] keynam = re.sub(r' [(]\d+[)]','',args.pem_file) keynam = re.sub(r'\.pem$','',keynam) new_inst = 'aws ec2 run-instances --image-id '+imagid+' --count=1 ' + \ '--key-name ' + keynam + ' ' + \ '--instance-type=t2.micro --security-group-ids ' + \ sec_group_id + ' --subnet-id ' + sid data = {'cmd': [['cmd',new_inst]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) result = json.loads(result[0][0]) docker_ip=result['Instances'][0]['PrivateIpAddress'] instance_id=result['Instances'][0]['InstanceId'] loop = 1 while loop == 1: # This creates an infinite loop time.sleep( 1 ) data = {'cmd': [['cmd','aws ec2 describe-instances --instance-ids '+instance_id+' 2>&1']]}; headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) result = json.loads(result[0][0]) print ('------------------') print (result['Reservations'][0]['Instances'][0]['State']['Name']) if result['Reservations'][0]['Instances'][0]['State']['Name'] == 'running': break print ('===================') print (docker_ip) print ("USERNAME/PEMFILE="+remuser+'/'+args.pem_file) data = {'cmd': [['connect_secure',{'ip':docker_ip,'login':'ec2-user','identityfile':'/home/'+remuser+'/FullAutoAPI/'+args.pem_file,'noretry':'1'}]]} time.sleep( 1 ) docker_server1=''; print ("\nGoing to Attempt to Connect to new Docker Server via ssh . . .\n") while loop == 1: # This creates an infinite loop headerz, content = http.request(url, "POST", body=dumps(data), \ headers=headers) result = json.loads(content) result = json.loads(result['result']) if re.search('Connection timed out|Connection refused',result[0][1]): print ("\n Waiting for sshd service to start . . .\n") time.sleep( 3 ) continue else: print ("GOT DOCKER!!!!"+result[0][1]) docker_server1=result[0][0] break time.sleep( 1 ) print ("DOCKER_SERVER1="+docker_server1) data = {'cmd': [['label',[docker_server1,'cmd','sudo yum -y install docker docker-registry']], ['label',[docker_server1,'cmd','sudo service docker start']], ['label',[docker_server1,'cmd','sudo usermod -a -G docker ec2-user']]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) print (result[0][1]) time.sleep( 1 ) data = {'cmd': [['label',[docker_server1,'close']]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) print (result) print ("USERNAME="+remuser+'/'+args.pem_file) data = {'cmd': [['connect_secure',{'ip':docker_ip,'login':'ec2-user', \ 'identityfile':'/home/'+remuser+'/FullAutoAPI/'+ args.pem_file,'noretry':'1'}]]} time.sleep( 1 ) docker_server1=''; while loop == 1: # This creates an infinite loop print ("GOING FOR CONNECT") headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) if re.search('Connection timed out|Connection refused',result[0][1]): print (result[0][1]) time.sleep( 1 ) continue else: print ("GOT DOCKER AGAIN!!!!") docker_server1=result[0][0] break time.sleep( 1 ) print ("DOCKER_SERVER1="+docker_server1) data = {'cmd': [['label',[docker_server1,'cmd','hostname']]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) print ("HOSTNAME="+str(result[0][0])) time.sleep( 1 ) data = {'cmd': [['label',[docker_server1,'cmd','docker info']]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) print ("DOCKER INFO="+str(result[0][0])) time.sleep( 1 ) data = {'cmd': [['label',[docker_server1,'docker_run','ubuntu /bin/bash']]]} headerz, content = http.request(url, "POST", body=dumps(data), headers=headers) result = json.loads(content) result = json.loads(result['result']) print ("DOCKER CONTAINER HOSTNAME="+str(result[0][0]))