def upgrade(self): """ Allows users to upgrade to the latest version of AppScale.""" contents_as_yaml = yaml.safe_load(self.read_appscalefile()) # Construct the appscale-upgrade command from argv and the contents of # the AppScalefile. command = [] if 'keyname' in contents_as_yaml: command.append("--keyname") command.append(contents_as_yaml['keyname']) if 'verbose' in contents_as_yaml and contents_as_yaml[ 'verbose'] == True: command.append("--verbose") if 'ips_layout' in contents_as_yaml: command.append('--ips_layout') command.append( base64.b64encode(yaml.dump(contents_as_yaml['ips_layout']))) if 'login' in contents_as_yaml: command.extend(['--login', contents_as_yaml['login']]) if 'test' in contents_as_yaml and contents_as_yaml['test'] == True: command.append('--test') options = ParseArgs(command, 'appscale-upgrade').args options.ips = yaml.safe_load(base64.b64decode(options.ips_layout)) AppScaleTools.upgrade(options)
def test_infrastructure_flags(self): # Specifying infastructure as EC2 or Eucalyptus is acceptable. argv_1 = self.cloud_argv[:] + [ '--infrastructure', 'ec2', '--machine', 'ami-ABCDEFG' ] actual_1 = ParseArgs(argv_1, self.function) self.assertEquals('ec2', actual_1.args.infrastructure) argv_2 = self.cloud_argv[:] + [ '--infrastructure', 'euca', '--machine', 'emi-ABCDEFG' ] actual_2 = ParseArgs(argv_2, self.function) self.assertEquals('euca', actual_2.args.infrastructure) # Specifying something else as the infrastructure is not acceptable. argv_3 = self.cloud_argv[:] + [ '--infrastructure', 'boocloud', '--machine', 'boo' ] self.assertRaises(SystemExit, ParseArgs, argv_3, self.function) # Specifying --machine when we're not running in a cloud is not acceptable. flexmock(os.path) os.path.should_call('exists') # set the fall-through os.path.should_receive('exists').with_args("ips.yaml").and_return(True) argv_4 = self.cluster_argv[:] + ['--machine', 'boo'] self.assertRaises(BadConfigurationException, ParseArgs, argv_4, self.function)
def test_table_flags(self): # throw in a mock that says our ips.yaml file exists flexmock(os.path) os.path.should_call('exists') # set the fall-through os.path.should_receive('exists').with_args('ips.yaml').and_return(True) # Specifying a table that isn't accepted should abort argv_1 = self.cluster_argv[:] + ['--table', 'non-existent-database'] self.assertRaises(SystemExit, ParseArgs, argv_1, self.function) # Specifying a table that is accepted should return that in the result argv_2 = self.cluster_argv[:] + ['--table', 'cassandra'] actual_2 = ParseArgs(argv_2, self.function) self.assertEquals('cassandra', actual_2.args.table) # Failing to specify a table should default to a predefined table args_3 = self.cluster_argv[:] actual_3 = ParseArgs(args_3, self.function) self.assertEquals(ParseArgs.DEFAULT_DATASTORE, actual_3.args.table) # Specifying a non-positive integer for n should abort argv_4 = self.cloud_argv[:] + ['--table', 'cassandra', '-n', '0'] self.assertRaises(BadConfigurationException, ParseArgs, argv_4, self.function) # Specifying a positive integer for n should be ok argv_5 = self.cloud_argv[:] + ['--table', 'cassandra', '-n', '2'] actual_5 = ParseArgs(argv_5, self.function) self.assertEquals(2, actual_5.args.replication)
def upgrade(self): """ Allows users to upgrade to the latest version of AppScale.""" contents_as_yaml = yaml.safe_load(self.read_appscalefile()) # Construct the appscale-upgrade command from argv and the contents of # the AppScalefile. command = [] if 'keyname' in contents_as_yaml: command.append("--keyname") command.append(contents_as_yaml['keyname']) if 'verbose' in contents_as_yaml and contents_as_yaml['verbose'] == True: command.append("--verbose") if 'ips_layout' in contents_as_yaml: command.append('--ips_layout') command.append( base64.b64encode(yaml.dump(contents_as_yaml['ips_layout']))) if 'login' in contents_as_yaml: command.extend(['--login', contents_as_yaml['login']]) if 'test' in contents_as_yaml and contents_as_yaml['test'] == True: command.append('--test') options = ParseArgs(command, 'appscale-upgrade').args options.ips = yaml.safe_load(base64.b64decode(options.ips_layout)) AppScaleTools.upgrade(options)
def test_ec2_creds_in_term_instances(self): function = "appscale-terminate-instances" # specifying EC2_ACCESS_KEY but not EC2_SECRET_KEY should fail argv = ["--EC2_ACCESS_KEY", "access_key"] self.assertRaises(BadConfigurationException, ParseArgs, argv, function) # specifying EC2_SECRET_KEY but not EC2_ACCESS_KEY should fail argv = ["--EC2_SECRET_KEY", "secret_key"] self.assertRaises(BadConfigurationException, ParseArgs, argv, function) # specifying both should result in them being set in the environment argv = ["--EC2_ACCESS_KEY", "baz", "--EC2_SECRET_KEY", "baz"] ParseArgs(argv, function) self.assertEquals("baz", os.environ['EC2_ACCESS_KEY']) self.assertEquals("baz", os.environ['EC2_SECRET_KEY']) # specifying a EC2_URL should result in it being set in the environment argv = [ "--EC2_ACCESS_KEY", "baz", "--EC2_SECRET_KEY", "baz", "--EC2_URL", "http://boo.baz" ] ParseArgs(argv, function) self.assertEquals("baz", os.environ['EC2_ACCESS_KEY']) self.assertEquals("baz", os.environ['EC2_SECRET_KEY']) self.assertEquals("http://boo.baz", os.environ['EC2_URL'])
def test_developer_flags(self): # Specifying force or test should have that carried over # to in the resulting hash argv_1 = self.cloud_argv[:] + ['--force'] actual_1 = ParseArgs(argv_1, self.function) self.assertEquals(True, actual_1.args.force) argv_2 = self.cloud_argv[:] + ['--test'] actual_2 = ParseArgs(argv_2, self.function) self.assertEquals(True, actual_2.args.test)
def up(self): """Starts an AppScale deployment with the configuration options from the AppScalefile in the current directory. Raises: AppScalefileException: If there is no AppScalefile in the current directory. """ contents = self.read_appscalefile() # If running in a cluster environment, we first need to set up SSH keys contents_as_yaml = yaml.safe_load(contents) if "ips_layout" in contents_as_yaml: ips_layout = base64.b64encode( yaml.dump(contents_as_yaml["ips_layout"])) if not "infrastructure" in contents_as_yaml: # Only run add-keypair if there is no ssh key present, # or if it doesn't log into all the machines specified. if not self.valid_ssh_key(contents_as_yaml): add_keypair_command = [] if "keyname" in contents_as_yaml: add_keypair_command.append("--keyname") add_keypair_command.append(str( contents_as_yaml["keyname"])) add_keypair_command.append("--ips_layout") add_keypair_command.append(ips_layout) options = ParseArgs(add_keypair_command, "appscale-add-keypair").args AppScaleTools.add_keypair(options) # Construct a run-instances command from the file's contents command = [] for key, value in contents_as_yaml.items(): if key in ["EC2_ACCESS_KEY", "EC2_SECRET_KEY", "EC2_URL"]: os.environ[key] = value continue if value is True: command.append(str("--%s" % key)) elif value is False: pass else: if key == "ips_layout": command.append("--ips_layout") command.append(ips_layout) else: command.append(str("--%s" % key)) command.append(str("%s" % value)) # Finally, call AppScaleTools.run_instances options = ParseArgs(command, "appscale-run-instances").args AppScaleTools.run_instances(options)
def test_add_master_nodes_in_virt_deployment(self): # don't use a 192.168.X.Y IP here, since sometimes we set our virtual # machines to boot with those addresses (and that can mess up our tests). ips_yaml = """ master: 1.2.3.4 database: 1.2.3.4 zookeeper: 1.2.3.4 appengine: 1.2.3.4 """ # mock out reading the yaml file, and slip in our own fake_yaml_file = flexmock(name='fake_yaml') fake_yaml_file.should_receive('read').and_return(ips_yaml) builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') # set the fall-through builtins.should_receive('open').with_args('/tmp/boo.yaml', 'r') \ .and_return(fake_yaml_file) argv = [ "--ips", "/tmp/boo.yaml", "--keyname", self.keyname ] options = ParseArgs(argv, self.function).args self.assertRaises(BadConfigurationException, AppScaleTools.add_instances, options)
def test_all_ok(self): # If the user wants to relocate their app to port X, and nothing else # runs on that port, this should succeed. # Assume that the AppController is running, so is our app, and that other # apps are not running on port 80. fake_appcontroller = flexmock(name='fake_appcontroller') fake_appcontroller.should_receive('get_app_info_map').with_args( 'the secret').and_return( json.dumps({ self.appid: { 'nginx': 8080 }, 'a-different-app': { 'nginx': 81 } })) fake_appcontroller.should_receive('relocate_app').with_args( self.appid, 80, 443, 'the secret').and_return("OK") flexmock(SOAPpy) SOAPpy.should_receive('SOAPProxy').with_args('https://public1:17443') \ .and_return(fake_appcontroller) argv = [ '--keyname', self.keyname, '--appname', self.appid, '--http_port', '80', '--https_port', '443' ] options = ParseArgs(argv, self.function).args AppScaleTools.relocate_app(options)
def test_upload_app_with_non_alpha_appid(self): # add in mocks so that there is an app.yaml, but with no appid set flexmock(os.path) os.path.should_call('exists') app_yaml_location = AppEngineHelper.get_app_yaml_location(self.app_dir) os.path.should_receive('exists').with_args(app_yaml_location) \ .and_return(True) # mock out reading the app.yaml file builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') # set the fall-through fake_app_yaml = flexmock(name="fake_app_yaml") fake_app_yaml.should_receive('read').and_return( yaml.dump({ 'application': 'baz*', 'runtime': 'python' })) builtins.should_receive('open').with_args(app_yaml_location, 'r') \ .and_return(fake_app_yaml) argv = ["--keyname", self.keyname, "--file", self.app_dir] options = ParseArgs(argv, self.function).args self.assertRaises(AppEngineConfigException, AppScaleTools.upload_app, options)
def test_appscale_with_ips_layout_flag_but_no_copy_id(self): # assume that we have ssh-keygen but not ssh-copy-id flexmock(subprocess) subprocess.should_receive('Popen').with_args(re.compile('hash ssh-keygen'), shell=True, stdout=self.fake_temp_file, stderr=subprocess.STDOUT) \ .and_return(self.success) flexmock(subprocess) subprocess.should_receive('Popen').with_args(re.compile('hash ssh-copy-id'), shell=True, stdout=self.fake_temp_file, stderr=subprocess.STDOUT) \ .and_return(self.failed) # don't use a 192.168.X.Y IP here, since sometimes we set our virtual # machines to boot with those addresses (and that can mess up our tests). ips_layout = yaml.safe_load(""" master : public1 database: public1 zookeeper: public2 appengine: public3 """) argv = [ "--ips_layout", base64.b64encode(yaml.dump(ips_layout)), "--keyname", self.keyname ] options = ParseArgs(argv, self.function).args self.assertRaises(BadConfigurationException, AppScaleTools.add_keypair, options)
def logs(self, location): """ 'logs' provides a cleaner experience for users than the appscale-gather-logs command, by using the configuration options present in the AppScalefile found in the current working directory. Args: location: The path on the local filesystem where logs should be copied to. Raises: AppScalefileException: If there is no AppScalefile in the current working directory. """ contents = self.read_appscalefile() contents_as_yaml = yaml.safe_load(contents) # construct the appscale-gather-logs command command = [] if 'keyname' in contents_as_yaml: command.append("--keyname") command.append(contents_as_yaml["keyname"]) command.append("--location") command.append(location) # and exec it options = ParseArgs(command, "appscale-gather-logs").args AppScaleTools.gather_logs(options)
def test_upload_java_app_with_no_appid(self): # add in mocks so that there is an appengine-web.xml, but with no appid set flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( AppEngineHelper.get_app_yaml_location( self.app_dir)).and_return(False) appengine_web_xml_location = AppEngineHelper.get_appengine_web_xml_location( self.app_dir) os.path.should_receive('exists').with_args( AppEngineHelper.get_appengine_web_xml_location( self.app_dir)).and_return(True) flexmock(AppEngineHelper).should_receive( 'get_app_id_from_app_config').and_return('app_id') flexmock(AppEngineHelper).should_receive( 'get_app_runtime_from_app_config').and_return('runtime') flexmock(LocalState).should_receive('get_secret_key').and_return() # mock out reading the app.yaml file builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') # set the fall-through fake_appengine_web_xml = flexmock(name="fake_appengine_web_xml") fake_appengine_web_xml.should_receive('read').and_return( "<baz></baz>\n" + "<application></application>") builtins.should_receive('open').with_args(appengine_web_xml_location, 'r') \ .and_return(fake_appengine_web_xml) argv = ["--keyname", self.keyname, "--file", self.app_dir] options = ParseArgs(argv, self.function).args self.assertRaises(AppEngineConfigException, AppScaleTools.upload_app, options)
def test_appscale_in_two_node_virt_deployment(self): # pretend that the place we're going to put logs into doesn't exist flexmock(os.path) os.path.should_call('exists') # set the fall-through os.path.should_receive('exists').with_args('/tmp/foobaz').and_return( False) # and mock out the mkdir operation flexmock(os) os.should_receive('mkdir').with_args('/tmp/foobaz').and_return() # next, mock out finding the login ip address os.path.should_receive('exists').with_args( LocalState.get_locations_json_location( self.keyname)).and_return(True) fake_nodes_json = flexmock(name="fake_nodes_json") fake_nodes_json.should_receive('read').and_return( json.dumps([{ "public_ip": "public1", "private_ip": "private1", "jobs": ["shadow", "login"] }])) builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') builtins.should_receive('open').with_args( LocalState.get_locations_json_location(self.keyname), 'r') \ .and_return(fake_nodes_json) # mock out writing the secret key to ~/.appscale, as well as reading it # later secret_key_location = LocalState.get_secret_key_location(self.keyname) fake_secret = flexmock(name="fake_secret") fake_secret.should_receive('read').and_return('the secret') builtins.should_receive('open').with_args(secret_key_location, 'r') \ .and_return(fake_secret) # and slip in a fake appcontroller to report on the two IP addrs fake_appcontroller = flexmock(name='fake_appcontroller') fake_appcontroller.should_receive('get_all_public_ips').with_args( 'the secret').and_return(json.dumps(['public1', 'public2'])) flexmock(SOAPpy) SOAPpy.should_receive('SOAPProxy').with_args('https://public1:17443') \ .and_return(fake_appcontroller) # fake the creation of the log directories locally os.should_receive('mkdir').with_args( '/tmp/foobaz/public1').and_return() os.should_receive('mkdir').with_args( '/tmp/foobaz/public2').and_return() # finally, fake the copying of the log files flexmock(subprocess) subprocess.should_receive('Popen').with_args(re.compile('/var/log/appscale'), shell=True, stdout=self.fake_temp_file, stderr=subprocess.STDOUT) \ .and_return(self.success) argv = ["--keyname", self.keyname, "--location", "/tmp/foobaz"] options = ParseArgs(argv, self.function).args AppScaleTools.gather_logs(options)
def test_fails_if_app_isnt_running(self): # If the user wants to relocate their app to port X, but their app isn't # even running, this should fail. # Assume that the AppController is running but our app isn't. flexmock(os.path) os.path.should_call('exists') # set the fall-through os.path.should_receive('exists').with_args( LocalState.get_locations_json_location( self.keyname)).and_return(True) fake_appcontroller = flexmock(name='fake_appcontroller') fake_appcontroller.should_receive('get_app_info_map').with_args( 'the secret').and_return(json.dumps({})) flexmock(SOAPpy) SOAPpy.should_receive('SOAPProxy').with_args('https://public1:17443') \ .and_return(fake_appcontroller) argv = [ '--keyname', self.keyname, '--appname', self.appid, '--http_port', '80', '--https_port', '443' ] options = ParseArgs(argv, self.function).args self.assertRaises(AppScaleException, AppScaleTools.relocate_app, options)
def test_disks_flag(self): # specifying a EBS mount or PD mount is only valid for EC2/Euca/GCE, so # fail on a cluster deployment. argv = self.cluster_argv[:] + ["--disks", "ABCDFEG"] self.assertRaises(BadConfigurationException, ParseArgs, argv, self.function) # if we get a --disk flag, fail if it's not a dict (after base64, yaml load) bad_disks_layout = yaml.load(""" public1, """) base64ed_bad_disks = base64.b64encode(yaml.dump(bad_disks_layout)) cloud_argv1 = self.cloud_argv[:] + ["--disks", base64ed_bad_disks] self.assertRaises(BadConfigurationException, ParseArgs, cloud_argv1, self.function) # passing in a dict should be fine, and result in us seeing the same value # for --disks that we passed in. disks = {'public1': 'vol-ABCDEFG'} good_disks_layout = yaml.load(""" public1 : vol-ABCDEFG """) base64ed_good_disks = base64.b64encode(yaml.dump(good_disks_layout)) cloud_argv2 = self.cloud_argv[:] + ["--disks", base64ed_good_disks] actual = ParseArgs(cloud_argv2, self.function).args self.assertEquals(disks, actual.disks)
def undeploy(self, appid): """ 'undeploy' is a more accessible way to tell an AppScale deployment to stop hosting a Google App Engine application than 'appscale-remove-app'. It calls that command with the configuration options found in the AppScalefile in the current working directory. Args: appid: The name of the application that we should remove. Raises: AppScalefileException: If there is no AppScalefile in the current working directory. """ contents = self.read_appscalefile() # Construct an remove-app command from the file's contents command = [] contents_as_yaml = yaml.safe_load(contents) if 'keyname' in contents_as_yaml: command.append("--keyname") command.append(contents_as_yaml['keyname']) if 'verbose' in contents_as_yaml and contents_as_yaml[ 'verbose'] == True: command.append("--verbose") if 'test' in contents_as_yaml and contents_as_yaml['test'] == True: command.append('--confirm') command.append("--appname") command.append(appid) # Finally, exec the command. Don't worry about validating it - # appscale-upload-app will do that for us. options = ParseArgs(command, "appscale-remove-app").args AppScaleTools.remove_app(options)
def test_max_spot_instance_price_flag(self): # if the user wants to use spot instances, that only works on ec2, so # abort if they're running on euca euca_argv = [ '--min', '1', '--max', '1', '--group', 'blargscale', '--infrastructure', 'euca', '--machine', 'emi-ABCDEFG', '--max_spot_price', '20' ] self.assertRaises(BadConfigurationException, ParseArgs, euca_argv, self.function) # also abort if they're running on a virtualized cluster cluster_argv = self.cluster_argv[:] + ['--max_spot_price', '20'] self.assertRaises(BadConfigurationException, ParseArgs, cluster_argv, self.function) # fail if running on EC2 and they didn't say that we should use spot # instances ec2_bad_argv = self.cloud_argv[:] + ['--max_spot_price', '20'] self.assertRaises(BadConfigurationException, ParseArgs, ec2_bad_argv, self.function) # succeed if they did say it ec2_argv = self.cloud_argv[:] + [ '--use_spot_instances', '--max_spot_price', '20.0' ] actual = ParseArgs(ec2_argv, self.function).args self.assertEquals(True, actual.use_spot_instances) self.assertEquals(20.0, actual.max_spot_price)
def get(self, property_regex): """ 'get' provides a cleaner experience for users than the appscale-get-property command, by using the configuration options present in the AppScalefile found in the current working directory. Args: property_regex: A regular expression indicating which AppController properties should be retrieved. Raises: AppScalefileException: If there is no AppScalefile in the current working directory. """ contents = self.read_appscalefile() contents_as_yaml = yaml.safe_load(contents) # construct the appscale-get-property command command = [] if 'keyname' in contents_as_yaml: command.append("--keyname") command.append(contents_as_yaml["keyname"]) command.append("--property") command.append(property_regex) # and exec it options = ParseArgs(command, "appscale-get-property").args return AppScaleTools.get_property(options)
def set(self, property_name, property_value): """ 'set' provides a cleaner experience for users than the appscale-set-property command, by using the configuration options present in the AppScalefile found in the current working directory. Args: property_name: A str naming the AppController instance variable that should be overwritten. property_value: The new value that should be used for the named property. Raises: AppScalefileException: If there is no AppScalefile in the current working directory. """ contents = self.read_appscalefile() contents_as_yaml = yaml.safe_load(contents) # construct the appscale-set-property command command = [] if 'keyname' in contents_as_yaml: command.append("--keyname") command.append(contents_as_yaml["keyname"]) command.append("--property_name") command.append(property_name) command.append("--property_value") command.append(property_value) # and exec it options = ParseArgs(command, "appscale-set-property").args AppScaleTools.set_property(options)
def test_remove_app_but_user_cancels_it(self): # mock out reading from stdin, and assume the user says 'no' builtins = flexmock(sys.modules['__builtin__']) builtins.should_receive('raw_input').and_return('no') argv = ["--appname", "blargapp"] options = ParseArgs(argv, self.function).args self.assertRaises(AppScaleException, AppScaleTools.remove_app, options)
def test_scp_flag(self): # first, make sure --scp fails if no arg is provided argv_1 = self.cloud_argv[:] + ['--scp'] self.assertRaises(SystemExit, ParseArgs, argv_1, self.function) argv_2 = self.cloud_argv[:] + ['--scp', '/tmp/booscale'] actual = ParseArgs(argv_2, self.function).args self.assertEquals('/tmp/booscale', actual.scp)
def test_describe_instances_with_two_nodes(self): # mock out writing the secret key to ~/.appscale, as well as reading it # later builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') # set the fall-through secret_key_location = LocalState.get_secret_key_location(self.keyname) fake_secret = flexmock(name="fake_secret") fake_secret.should_receive('read').and_return('the secret') fake_secret.should_receive('write').and_return() builtins.should_receive('open').with_args(secret_key_location, 'r') \ .and_return(fake_secret) # mock out the SOAP call to the AppController and assume it succeeded fake_appcontroller = flexmock(name='fake_appcontroller') fake_appcontroller.should_receive('get_all_public_ips').with_args('the secret') \ .and_return(json.dumps(['public1', 'public2'])) fake_appcontroller.should_receive('status').with_args('the secret') \ .and_return('nothing interesting here') \ .and_return('Database is at not-up-yet') \ .and_return('Database is at 1.2.3.4') flexmock(SOAPpy) SOAPpy.should_receive('SOAPProxy').with_args('https://public1:17443') \ .and_return(fake_appcontroller) SOAPpy.should_receive('SOAPProxy').with_args('https://public2:17443') \ .and_return(fake_appcontroller) # mock out reading the locations.json file, and slip in our own json flexmock(os.path) os.path.should_call('exists') # set the fall-through os.path.should_receive('exists').with_args( LocalState.get_locations_json_location( self.keyname)).and_return(True) fake_nodes_json = flexmock(name="fake_nodes_json") fake_nodes_json.should_receive('read').and_return( json.dumps([ { "public_ip": "public1", "private_ip": "private1", "jobs": ["shadow", "login"] }, { "public_ip": "public2", "private_ip": "private2", "jobs": ["appengine"] }, ])) fake_nodes_json.should_receive('write').and_return() builtins.should_receive('open').with_args( LocalState.get_locations_json_location(self.keyname), 'r') \ .and_return(fake_nodes_json) # assume that there are two machines running in our deployment argv = ["--keyname", self.keyname] options = ParseArgs(argv, self.function).args AppScaleTools.describe_instances(options)
def test_reset_password_for_user_that_doesnt_exist(self): # put in a mock for reading the secret file builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') # set the fall-through secret_key_location = LocalState.get_secret_key_location(self.keyname) fake_secret = flexmock(name="fake_secret") fake_secret.should_receive('read').and_return('the secret') builtins.should_receive('open').with_args(secret_key_location, 'r') \ .and_return(fake_secret) # mock out reading the username and new password from the user builtins.should_receive('raw_input').and_return('*****@*****.**') flexmock(getpass) getpass.should_receive('getpass').and_return('the password') # mock out finding the login node's IP address from the json file flexmock(os.path) os.path.should_call('exists') # set the fall-through os.path.should_receive('exists').with_args( LocalState.get_locations_json_location( self.keyname)).and_return(True) fake_nodes_json = flexmock(name="fake_secret") fake_nodes_json.should_receive('read').and_return( json.dumps([{ 'public_ip': 'public1', 'private_ip': 'private1', 'jobs': ['login', 'db_master'] }])) builtins.should_receive('open').with_args( LocalState.get_locations_json_location(self.keyname), 'r') \ .and_return(fake_nodes_json) # mock out grabbing the userappserver ip from an appcontroller fake_appcontroller = flexmock(name='fake_appcontroller') fake_appcontroller.should_receive('status').with_args('the secret') \ .and_return('nothing interesting here') \ .and_return('Database is at not-up-yet') \ .and_return('Database is at public1') flexmock(SOAPpy) SOAPpy.should_receive('SOAPProxy').with_args('https://*****:*****@foo.goo', str, 'the secret').and_return('Error: user does not exist') SOAPpy.should_receive('SOAPProxy').with_args('https://public1:4343') \ .and_return(fake_userappserver) argv = ["--keyname", self.keyname] options = ParseArgs(argv, self.function).args self.assertRaises(SystemExit, AppScaleTools.reset_password, options)
def test_remove_app_and_app_is_running(self): # mock out reading from stdin, and assume the user says 'YES' builtins = flexmock(sys.modules['__builtin__']) builtins.should_receive('raw_input').and_return('YES') # mock out reading the secret key builtins.should_call('open') # set the fall-through secret_key_location = LocalState.get_secret_key_location(self.keyname) fake_secret = flexmock(name="fake_secret") fake_secret.should_receive('read').and_return('the secret') builtins.should_receive('open').with_args(secret_key_location, 'r') \ .and_return(fake_secret) # mock out the SOAP call to the AppController and assume it succeeded fake_appcontroller = flexmock(name='fake_appcontroller') fake_appcontroller.should_receive('status').with_args('the secret') \ .and_return('Database is at public1') fake_appcontroller.should_receive('stop_app').with_args( 'blargapp', 'the secret').and_return('OK') fake_appcontroller.should_receive('is_app_running').with_args( 'blargapp', 'the secret').and_return(True).and_return(True).and_return(False) flexmock(SOAPpy) SOAPpy.should_receive('SOAPProxy').with_args('https://public1:17443') \ .and_return(fake_appcontroller) # mock out reading the locations.json file, and slip in our own json flexmock(os.path) os.path.should_call('exists') # set the fall-through os.path.should_receive('exists').with_args( LocalState.get_locations_json_location( self.keyname)).and_return(True) fake_nodes_json = flexmock(name="fake_nodes_json") fake_nodes_json.should_receive('read').and_return( json.dumps([{ "public_ip": "public1", "private_ip": "private1", "jobs": ["shadow", "login"] }])) fake_nodes_json.should_receive('write').and_return() builtins.should_receive('open').with_args( LocalState.get_locations_json_location(self.keyname), 'r') \ .and_return(fake_nodes_json) # mock out calls to the UserAppServer and presume that the app does exist fake_userappserver = flexmock(name='fake_uaserver') fake_userappserver.should_receive('get_app_data').with_args( 'blargapp', 'the secret').and_return('\nnum_ports:2\n') SOAPpy.should_receive('SOAPProxy').with_args('https://public1:4343') \ .and_return(fake_userappserver) argv = ["--appname", "blargapp", "--keyname", self.keyname] options = ParseArgs(argv, self.function).args AppScaleTools.remove_app(options)
def test_scaling_flags(self): # Specifying a value for add_to_existing should fail argv_1 = ["--add_to_existing", "boo"] self.assertRaises(SystemExit, ParseArgs, argv_1, "appscale-add-keypair") # not specifying a value should set it to true argv_2 = ["--add_to_existing"] actual = ParseArgs(argv_2, "appscale-add-keypair") self.assertEquals(True, actual.args.add_to_existing)
def test_login_flag(self): # if the user wants to override the URL where we log in at, make sure it # fails if they don't give us a URL to log in to argv_1 = self.cloud_argv[:] + ['--login_host'] self.assertRaises(SystemExit, ParseArgs, argv_1, self.function) # and it should succeed if they do give us the URL argv_2 = self.cloud_argv[:] + ['--login_host', 'www.booscale.com'] actual = ParseArgs(argv_2, self.function).args self.assertEquals('www.booscale.com', actual.login_host)
def test_terminate_when_not_running(self): # let's say that there's no locations.yaml file, which means appscale isn't # running, so we should throw up and die flexmock(os.path) os.path.should_call('exists') # set up the fall-through os.path.should_receive('exists').with_args( LocalState.get_secret_key_location(self.keyname)).and_return(False) argv = ["--keyname", self.keyname, "--test"] options = ParseArgs(argv, self.function).args self.assertRaises(AppScaleException, AppScaleTools.terminate_instances, options)
def test_ips_layout_flag(self): # first, make sure that the flag works ips_layout = yaml.load(""" 'controller' : public1, 'servers' : public2' """) base64ed_ips = base64.b64encode(yaml.dump(ips_layout)) argv = ['--ips_layout', base64ed_ips] actual = ParseArgs(argv, self.function).args self.assertEquals(base64ed_ips, actual.ips_layout) # next, make sure that it got assigned to ips self.assertEquals(ips_layout, actual.ips)
def test_instance_types(self): # Not specifying an instance type should default to a predetermined # value. argv_1 = self.cloud_argv[:] actual = ParseArgs(argv_1, self.function) self.assertEquals(ParseArgs.DEFAULT_EC2_INSTANCE_TYPE, \ actual.args.instance_type) # Specifying m1.large as the instance type is acceptable. argv_2 = self.cloud_argv[:] + [ '--infrastructure', 'ec2', '--machine', 'ami-ABCDEFG', '--instance_type', 'm1.large' ] actual = ParseArgs(argv_2, self.function) self.assertEquals("m1.large", actual.args.instance_type) # Specifying blarg1.humongous as the instance type is not # acceptable. argv_3 = self.cloud_argv[:] + [ '--infrastructure', 'ec2', '--machine', 'ami-ABCDEFG', '--instance_type', 'blarg1.humongous' ] self.assertRaises(SystemExit, ParseArgs, argv_3, self.function)
def test_flags_that_cause_program_abort(self): # using a flag that isn't acceptable should raise # an exception argv_1 = ['--boo!'] self.assertRaises(SystemExit, ParseArgs, argv_1, self.function) # the version flag should quit and print the current # version of the tools argv_2 = ['--version'] try: ParseArgs(argv_2, self.function) raise except SystemExit: pass