def testDownWithEC2EnvironmentVariables(self): # if the user wants us to use their EC2 credentials when running AppScale, # we should make sure they get set appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'machine' : 'ami-ABCDEFG', 'keyname' : 'bookey', 'group' : 'boogroup', 'min_machines' : 1, 'max_machines' : 1, 'EC2_ACCESS_KEY' : 'access key', 'EC2_SECRET_KEY' : 'secret key' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-terminate-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('terminate_instances') appscale.down() self.assertEquals('access key', os.environ['EC2_ACCESS_KEY']) self.assertEquals('secret key', os.environ['EC2_SECRET_KEY'])
def testUndeployWithCloudAppScalefile(self): # calling 'appscale undeploy app' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-remove-app' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'machine' : 'ami-ABCDEFG', 'keyname' : 'bookey', 'group' : 'boogroup', 'verbose' : True, 'min_machines' : 1, 'max_machines' : 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-run-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('remove_app') app = 'barapp' appscale.undeploy(app)
def testDeployWithCloudAppScalefile(self): # calling 'appscale deploy app' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-upload-app' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'verbose': True, 'min_machines': 1, 'max_machines': 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-run-instances call fake_port = 8080 fake_host = 'fake_host' flexmock(AppScaleTools) AppScaleTools.should_receive('upload_app').and_return( (fake_host, fake_port)) AppScaleTools.should_receive('update_indexes') AppScaleTools.should_receive('update_cron') AppScaleTools.should_receive('update_queues') app = '/bar/app' (host, port) = appscale.deploy(app) self.assertEquals(fake_host, host) self.assertEquals(fake_port, port)
def testDeployWithCloudAppScalefileAndTestFlag(self): # same as before, but with the 'test' flag in our AppScalefile appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'machine' : 'ami-ABCDEFG', 'keyname' : 'bookey', 'group' : 'boogroup', 'verbose' : True, 'min_machines' : 1, 'max_machines' : 1, 'test' : True } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-run-instances call fake_port = 8080 fake_host = 'fake_host' flexmock(AppScaleTools) AppScaleTools.should_receive('upload_app').and_return( (fake_host, fake_port)) AppScaleTools.should_receive('update_indexes') AppScaleTools.should_receive('update_cron') AppScaleTools.should_receive('update_queues') app = '/bar/app' (host, port) = appscale.deploy(app) self.assertEquals(fake_host, host) self.assertEquals(fake_port, port)
def testDeployWithCloudAppScalefileAndTestFlag(self): # same as before, but with the 'test' flag in our AppScalefile appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'verbose': True, 'min_machines': 1, 'max_machines': 1, 'test': True } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-run-instances call fake_port = 8080 fake_host = 'fake_host' flexmock(AppScaleTools) AppScaleTools.should_receive('upload_app').and_return( (fake_host, fake_port)) AppScaleTools.should_receive('update_indexes') AppScaleTools.should_receive('update_cron') AppScaleTools.should_receive('update_queues') app = '/bar/app' (host, port) = appscale.deploy(app) self.assertEquals(fake_host, host) self.assertEquals(fake_port, port)
def testDeployWithCloudAppScalefile(self): # calling 'appscale deploy app' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-upload-app' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'machine' : 'ami-ABCDEFG', 'keyname' : 'bookey', 'group' : 'boogroup', 'verbose' : True, 'min_machines' : 1, 'max_machines' : 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-run-instances call fake_port = 8080 fake_host = 'fake_host' flexmock(AppScaleTools) AppScaleTools.should_receive('upload_app').and_return( (fake_host, fake_port)) AppScaleTools.should_receive('update_indexes') AppScaleTools.should_receive('update_cron') AppScaleTools.should_receive('update_queues') app = '/bar/app' (host, port) = appscale.deploy(app) self.assertEquals(fake_host, host) self.assertEquals(fake_port, port)
def testDownWithEC2EnvironmentVariables(self): # if the user wants us to use their EC2 credentials when running AppScale, # we should make sure they get set appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'min_machines': 1, 'max_machines': 1, 'EC2_ACCESS_KEY': 'access key', 'EC2_SECRET_KEY': 'secret key' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-terminate-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('terminate_instances') appscale.down() self.assertEquals('access key', os.environ['EC2_ACCESS_KEY']) self.assertEquals('secret key', os.environ['EC2_SECRET_KEY'])
def testUndeployWithCloudAppScalefile(self): # calling 'appscale undeploy app' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-remove-app' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'verbose': True, 'min_machines': 1, 'max_machines': 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-run-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('remove_app') app = 'barapp' appscale.undeploy(app)
def testTailWithIndexInBounds(self): # calling 'appscale tail 1 *' should tail from the second node # (nodes[1]). If there are two nodes in this deployment, # we should tail from it successfully appscale = AppScale() contents = { 'keyname' : 'boo' } yaml_dumped_contents = yaml.dump(contents) one = { 'public_ip' : 'blarg' } two = { 'public_ip' : 'blarg2' } nodes = {'node_info': [one, two]} nodes_contents = json.dumps(nodes) mock = self.addMockForAppScalefile(appscale, yaml_dumped_contents) (mock.should_receive('open') .with_args(appscale.get_locations_json_file('boo')) .and_return(flexmock(read=lambda: nodes_contents))) flexmock(subprocess) subprocess.should_receive('call').with_args(["ssh", "-o", "StrictHostkeyChecking=no", "-i", appscale.get_key_location('boo'), "root@blarg2", "tail -F /var/log/appscale/c*"]).and_return().once() appscale.tail(1, "c*")
def testTailWithNoNodesJson(self): # calling 'appscale tail' when there isn't a locations.json # file should throw up and die appscale = AppScale() contents = {'keyname': 'boo'} yaml_dumped_contents = yaml.dump(contents) mock = self.addMockForAppScalefile(appscale, yaml_dumped_contents) (mock.should_receive('open').with_args( appscale.get_locations_json_file('boo')).and_raise(IOError)) self.assertRaises(AppScaleException, appscale.tail, 0, "")
def testTailWithNoNodesJson(self): # calling 'appscale tail' when there isn't a locations.json # file should throw up and die appscale = AppScale() contents = { 'keyname' : 'boo' } yaml_dumped_contents = yaml.dump(contents) mock = self.addMockForAppScalefile(appscale, yaml_dumped_contents) (mock.should_receive('open') .with_args(appscale.get_locations_json_file('boo')) .and_raise(IOError)) self.assertRaises(AppScaleException, appscale.tail, 0, "")
def testUpWithCloudAppScalefile(self): # calling 'appscale up' if there is an AppScalefile present # should call appscale-run-instances with the given config # params. here, we assume that the file is intended for use # on EC2 appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'instance_type': 'm3.medium', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'min_machines': 1, 'max_machines': 1, 'zone': 'my-zone-1b' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) # throw in some mocks for the argument parsing for credential in EC2Agent.REQUIRED_CREDENTIALS: os.environ[credential] = "baz" # finally, pretend that our ec2 zone and image exists fake_ec2 = flexmock(name="fake_ec2") fake_ec2.should_receive('get_all_instances') fake_ec2.should_receive('get_all_zones').with_args('my-zone-1b') \ .and_return('anything') fake_ec2.should_receive('get_image').with_args('ami-ABCDEFG') \ .and_return() flexmock(boto.ec2) boto.ec2.should_receive('connect_to_region').with_args( 'my-zone-1', aws_access_key_id='baz', aws_secret_access_key='baz').and_return(fake_ec2) # finally, mock out the actual appscale-run-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('run_instances') appscale.up()
def testUpWithEC2EnvironmentVariables(self): # if the user wants us to use their EC2 credentials when running AppScale, # we should make sure they get set appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'instance_type': 'm3.medium', 'keyname': 'bookey', 'group': 'boogroup', 'min_machines': 1, 'max_machines': 1, 'EC2_ACCESS_KEY': 'access key', 'EC2_SECRET_KEY': 'secret key', 'zone': 'my-zone-1b' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) # finally, pretend that our ec2 zone/image to use exist fake_ec2 = flexmock(name="fake_ec2") fake_ec2.should_receive('get_all_instances') fake_ec2.should_receive('get_all_zones').with_args('my-zone-1b') \ .and_return('anything') fake_ec2.should_receive('get_image').with_args('ami-ABCDEFG') \ .and_return() flexmock(boto.ec2) boto.ec2.should_receive('connect_to_region').with_args( 'my-zone-1', aws_access_key_id='access key', aws_secret_access_key='secret key').and_return(fake_ec2) # finally, mock out the actual appscale-run-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('run_instances') appscale.up() self.assertEquals('access key', os.environ['EC2_ACCESS_KEY']) self.assertEquals('secret key', os.environ['EC2_SECRET_KEY'])
def testUpWithEC2EnvironmentVariables(self): # if the user wants us to use their EC2 credentials when running AppScale, # we should make sure they get set appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'machine' : 'ami-ABCDEFG', 'instance_type' : 'm3.medium', 'keyname' : 'bookey', 'group' : 'boogroup', 'min_machines' : 1, 'max_machines' : 1, 'EC2_ACCESS_KEY' : 'access key', 'EC2_SECRET_KEY' : 'secret key', 'zone' : 'my-zone-1b' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) # finally, pretend that our ec2 zone/image to use exist fake_ec2 = flexmock(name="fake_ec2") fake_ec2.should_receive('get_all_instances') fake_ec2.should_receive('get_all_zones').with_args('my-zone-1b') \ .and_return('anything') fake_ec2.should_receive('get_image').with_args('ami-ABCDEFG') \ .and_return() flexmock(boto.ec2) boto.ec2.should_receive('connect_to_region').with_args('my-zone-1', aws_access_key_id='access key', aws_secret_access_key='secret key').and_return(fake_ec2) # finally, mock out the actual appscale-run-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('run_instances') appscale.up() self.assertEquals('access key', os.environ['EC2_ACCESS_KEY']) self.assertEquals('secret key', os.environ['EC2_SECRET_KEY'])
def testUpWithCloudAppScalefile(self): # calling 'appscale up' if there is an AppScalefile present # should call appscale-run-instances with the given config # params. here, we assume that the file is intended for use # on EC2 appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'instance_type' : 'm3.medium', 'machine' : 'ami-ABCDEFG', 'keyname' : 'bookey', 'group' : 'boogroup', 'min_machines' : 1, 'max_machines' : 1, 'zone' : 'my-zone-1b' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) # throw in some mocks for the argument parsing for credential in EC2Agent.REQUIRED_CREDENTIALS: os.environ[credential] = "baz" # finally, pretend that our ec2 zone and image exists fake_ec2 = flexmock(name="fake_ec2") fake_ec2.should_receive('get_all_instances') fake_ec2.should_receive('get_all_zones').with_args('my-zone-1b') \ .and_return('anything') fake_ec2.should_receive('get_image').with_args('ami-ABCDEFG') \ .and_return() flexmock(boto.ec2) boto.ec2.should_receive('connect_to_region').with_args('my-zone-1', aws_access_key_id='baz', aws_secret_access_key='baz').and_return(fake_ec2) # finally, mock out the actual appscale-run-instances call flexmock(AppScaleTools) AppScaleTools.should_receive('run_instances') appscale.up()
def testUpWithMalformedClusterAppScalefile(self): # if we try to use an IPs layout that isn't a dictionary, we should throw up # and die appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file, with an IPs layout that is a str contents = { 'ips_layout': "'master' 'ip1' 'appengine' 'ip1'", 'keyname': 'boobazblarg', 'group': 'boobazblarg', 'EC2_ACCESS_KEY': '', 'EC2_SECRET_KEY': '' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) # finally, mock out the actual appscale tools calls. since we're running # via a cluster, this means we call add-keypair to set up SSH keys, then # run-instances to start appscale flexmock(AppScaleTools) AppScaleTools.should_receive('add_keypair') self.assertRaises(BadConfigurationException, appscale.up)
def test_get_head_node(self): shadow_node_1 = {'public_ip': 'public2', 'roles': ['shadow']} appengine_node = {'public_ip': 'public1', 'roles': ['appengine']} shadow_node_2 = {'public_ip': 'public3', 'roles': ['shadow']} appscale = AppScale() # If the list of nodes does not have a node with the shadow role, the # tools should raise an AppScaleException. with self.assertRaises(AppScaleException): appscale.get_head_node([appengine_node]) # If the list of nodes contains any nodes with the shadow role, the tools # should return the public IP address of the first node which has that # role. self.assertEqual(shadow_node_1['public_ip'], appscale.get_head_node([shadow_node_1, appengine_node, shadow_node_2]))
def testUndeployWithNoAppScalefile(self): # calling 'appscale undeploy' with no AppScalefile in the local # directory should throw up and die appscale = AppScale() self.addMockForNoAppScalefile(appscale) appid = "barapp" self.assertRaises(AppScalefileException, appscale.undeploy, appid)
def testRelocateWithNoAppScalefile(self): # calling 'appscale relocate' with no AppScalefile in the local directory # should throw up and die appscale = AppScale() self.addMockForNoAppScalefile(appscale) self.assertRaises(AppScalefileException, appscale.relocate, 'myapp', 80, 443)
def test_get_head_node(self): shadow_node_1 = {'public_ip': 'public2', 'roles': ['shadow']} appengine_node = {'public_ip': 'public1', 'roles': ['appengine']} shadow_node_2 = {'public_ip': 'public3', 'roles': ['shadow']} appscale = AppScale() # If the list of nodes does not have a node with the shadow role, the # tools should raise an AppScaleException. with self.assertRaises(AppScaleException): appscale.get_head_node([appengine_node]) # If the list of nodes contains any nodes with the shadow role, the tools # should return the public IP address of the first node which has that # role. self.assertEqual( shadow_node_1['public_ip'], appscale.get_head_node( [shadow_node_1, appengine_node, shadow_node_2]))
def testInitWithNoAppScalefile(self): # calling 'appscale init cloud' if there's no AppScalefile in the local # directory should write a new cloud config file there appscale = AppScale() flexmock(os) os.should_receive('getcwd').and_return('/boo') flexmock(os.path) os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(False) # mock out the actual writing of the template file flexmock(shutil) shutil.should_receive('copy').with_args( appscale.TEMPLATE_APPSCALEFILE, '/boo/' + appscale.APPSCALEFILE) \ .and_return() appscale.init()
def testTailWithIndexOutOfBounds(self): # calling 'appscale tail 1 *' should tail from the second node # (nodes[1]). If there's only one node in this deployment, # we should throw up and die appscale = AppScale() contents = {'keyname': 'boo'} yaml_dumped_contents = yaml.dump(contents) one = {'public_ip': 'blarg'} nodes = {'node_info': [one]} nodes_contents = json.dumps(nodes) mock = self.addMockForAppScalefile(appscale, yaml_dumped_contents) (mock.should_receive('open').with_args( appscale.get_locations_json_file('boo')).and_return( flexmock(read=lambda: nodes_contents))) self.assertRaises(AppScaleException, appscale.tail, 1, '')
def testUpWithClusterAppScalefile(self): # calling 'appscale up' if there is an AppScalefile present # should call appscale-run-instances with the given config # params. here, we assume that the file is intended for use # on a virtualized cluster appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'ips_layout': { 'master': 'ip1', 'appengine': 'ip1', 'database': 'ip2', 'zookeeper': 'ip2' }, 'keyname': 'boobazblarg', 'group': 'boobazblarg' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) # for this test, let's say that we don't have an SSH key already # set up for ip1 and ip2 # TODO(cgb): Add in tests where we have a key for ip1 but not ip2, # and the case where we have a key but it doesn't work key_path = os.path.expanduser('~/.appscale/boobazblarg.key') os.path.should_receive('exists').with_args(key_path).and_return(False) # finally, mock out the actual appscale tools calls. since we're running # via a cluster, this means we call add-keypair to set up SSH keys, then # run-instances to start appscale flexmock(AppScaleTools) AppScaleTools.should_receive('add_keypair') AppScaleTools.should_receive('run_instances') appscale.up()
def testGetLogsWithKeyname(self): # calling 'appscale logs dir' with a keyname should produce # a command to exec with the --keyname flag appscale = AppScale() contents = {"keyname": "boo"} yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # mock out the actual call to appscale-gather-logs flexmock(AppScaleTools) AppScaleTools.should_receive('run_instances') self.assertRaises(BadConfigurationException, appscale.logs, '/baz')
def testTailWithIndexOutOfBounds(self): # calling 'appscale tail 1 *' should tail from the second node # (nodes[1]). If there's only one node in this deployment, # we should throw up and die appscale = AppScale() contents = { 'keyname' : 'boo' } yaml_dumped_contents = yaml.dump(contents) one = { 'public_ip' : 'blarg' } nodes = {'node_info': [one]} nodes_contents = json.dumps(nodes) mock = self.addMockForAppScalefile(appscale, yaml_dumped_contents) (mock.should_receive('open') .with_args(appscale.get_locations_json_file('boo')) .and_return(flexmock(read=lambda: nodes_contents))) self.assertRaises(AppScaleException, appscale.tail, 1, '')
def test_register(self): appscale_yaml = {'keyname': 'boo'} deployment = { 'name': 'bar', 'deployment_id': 'baz', 'nodes': [{ 'public_ip': 'public1', 'jobs': ['shadow'] }] } flexmock(AppScale).should_receive('read_appscalefile')\ .and_return(yaml.dump(appscale_yaml)) flexmock(yaml).should_receive('safe_load').and_return( {'keyname': 'boo'}) flexmock(AppScale).should_receive('get_nodes')\ .and_return(deployment['nodes']) flexmock(AppScale).should_receive('get_head_node')\ .and_return(deployment['nodes'][0]) flexmock(RegistrationHelper).should_receive('update_deployment') \ .and_return(deployment) flexmock(RegistrationHelper).should_receive('set_deployment_id') \ .and_return() appscale = AppScale() # If the deployment already has an ID and it differs from the one given, # the tools should raise an AppScaleException. existing_deployment_id = 'blarg' flexmock(RegistrationHelper).should_receive('appscale_has_deployment_id')\ .and_return(True) flexmock(RegistrationHelper).should_receive('get_deployment_id')\ .and_return(existing_deployment_id) with self.assertRaises(AppScaleException): appscale.register(deployment['deployment_id']) # If the existing deployment ID is the same as the given deployment ID, # the tools should try to complete the registration with the portal. existing_deployment_id = 'baz' flexmock(RegistrationHelper).should_receive('get_deployment_id') \ .and_return(existing_deployment_id) appscale.register(deployment['deployment_id']) # If the deployment does not have an ID set, the tools should try to # complete the registration. flexmock(RegistrationHelper).should_receive('appscale_has_deployment_id')\ .and_return(False) appscale.register(deployment['deployment_id'])
def testTailWithIndexInBounds(self): # calling 'appscale tail 1 *' should tail from the second node # (nodes[1]). If there are two nodes in this deployment, # we should tail from it successfully appscale = AppScale() contents = {'keyname': 'boo'} yaml_dumped_contents = yaml.dump(contents) one = {'public_ip': 'blarg'} two = {'public_ip': 'blarg2'} nodes = {'node_info': [one, two]} nodes_contents = json.dumps(nodes) mock = self.addMockForAppScalefile(appscale, yaml_dumped_contents) (mock.should_receive('open').with_args( appscale.get_locations_json_file('boo')).and_return( flexmock(read=lambda: nodes_contents))) flexmock(subprocess) subprocess.should_receive('call').with_args([ "ssh", "-o", "StrictHostkeyChecking=no", "-i", appscale.get_key_location('boo'), "root@blarg2", "tail -F /var/log/appscale/c*" ]).and_return().once() appscale.tail(1, "c*")
def testCreateUserWithAppScalefile(self): # calling 'appscale create-user' with AppScalefile in the local appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'verbose': True, 'min_machines': 1, 'max_machines': 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-create-user call flexmock(AppScaleTools) AppScaleTools.should_receive('create_user') appscale.create_user()
def testInitWithAppScalefile(self): # calling 'appscale init cloud' if there is an AppScalefile in the local # directory should throw up and die appscale = AppScale() flexmock(os) os.should_receive('getcwd').and_return('/boo') flexmock(os.path) os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) self.assertRaises(AppScalefileException, appscale.init)
def testUpWithClusterAppScalefile(self): # calling 'appscale up' if there is an AppScalefile present # should call appscale-run-instances with the given config # params. here, we assume that the file is intended for use # on a virtualized cluster appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'ips_layout': {'master': 'ip1', 'appengine': 'ip1', 'database': 'ip2', 'zookeeper': 'ip2'}, 'keyname': 'boobazblarg', 'group': 'boobazblarg' } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) flexmock(os.path) os.path.should_call('exists') os.path.should_receive('exists').with_args( '/boo/' + appscale.APPSCALEFILE).and_return(True) # for this test, let's say that we don't have an SSH key already # set up for ip1 and ip2 # TODO(cgb): Add in tests where we have a key for ip1 but not ip2, # and the case where we have a key but it doesn't work key_path = os.path.expanduser('~/.appscale/boobazblarg.key') os.path.should_receive('exists').with_args(key_path).and_return(False) # finally, mock out the actual appscale tools calls. since we're running # via a cluster, this means we call add-keypair to set up SSH keys, then # run-instances to start appscale flexmock(AppScaleTools) AppScaleTools.should_receive('add_keypair') AppScaleTools.should_receive('run_instances') appscale.up()
def testSetPropertyWithAppScalefile(self): # calling 'appscale set' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-get-property' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'verbose': True, 'min_machines': 1, 'max_machines': 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-set-property call flexmock(AppScaleTools) AppScaleTools.should_receive('set_property') appscale.set('key', 'value')
def testRelocateWithAppScalefile(self): # calling 'appscale relocate' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-relocate-app' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure': 'ec2', 'machine': 'ami-ABCDEFG', 'keyname': 'bookey', 'group': 'boogroup', 'verbose': True, 'min': 1, 'max': 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-relocate-app call flexmock(AppScaleTools) AppScaleTools.should_receive('relocate_app') appscale.relocate('myapp', 80, 443)
def testRelocateWithAppScalefile(self): # calling 'appscale relocate' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-relocate-app' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'machine' : 'ami-ABCDEFG', 'keyname' : 'bookey', 'group' : 'boogroup', 'verbose' : True, 'min' : 1, 'max' : 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-relocate-app call flexmock(AppScaleTools) AppScaleTools.should_receive('relocate_app') appscale.relocate('myapp', 80, 443)
def testSetPropertyWithAppScalefile(self): # calling 'appscale set' with an AppScalefile in the local # directory should collect any parameters needed for the # 'appscale-get-property' command and then exec it appscale = AppScale() # Mock out the actual file reading itself, and slip in a YAML-dumped # file contents = { 'infrastructure' : 'ec2', 'machine' : 'ami-ABCDEFG', 'keyname' : 'bookey', 'group' : 'boogroup', 'verbose' : True, 'min_machines' : 1, 'max_machines' : 1 } yaml_dumped_contents = yaml.dump(contents) self.addMockForAppScalefile(appscale, yaml_dumped_contents) # finally, mock out the actual appscale-set-property call flexmock(AppScaleTools) AppScaleTools.should_receive('set_property') appscale.set('key', 'value')
def test_register(self): appscale_yaml = {'keyname': 'boo'} deployment = { 'name': 'bar', 'deployment_id': 'baz', 'nodes': [{'public_ip': 'public1', 'jobs': ['shadow']}] } flexmock(AppScale).should_receive('read_appscalefile')\ .and_return(yaml.dump(appscale_yaml)) flexmock(yaml).should_receive('safe_load').and_return({'keyname': 'boo'}) flexmock(AppScale).should_receive('get_nodes')\ .and_return(deployment['nodes']) flexmock(AppScale).should_receive('get_head_node')\ .and_return(deployment['nodes'][0]) flexmock(RegistrationHelper).should_receive('update_deployment') \ .and_return(deployment) flexmock(RegistrationHelper).should_receive('set_deployment_id') \ .and_return() appscale = AppScale() # If the deployment already has an ID and it differs from the one given, # the tools should raise an AppScaleException. existing_deployment_id = 'blarg' flexmock(RegistrationHelper).should_receive('appscale_has_deployment_id')\ .and_return(True) flexmock(RegistrationHelper).should_receive('get_deployment_id')\ .and_return(existing_deployment_id) with self.assertRaises(AppScaleException): appscale.register(deployment['deployment_id']) # If the existing deployment ID is the same as the given deployment ID, # the tools should try to complete the registration with the portal. existing_deployment_id = 'baz' flexmock(RegistrationHelper).should_receive('get_deployment_id') \ .and_return(existing_deployment_id) appscale.register(deployment['deployment_id']) # If the deployment does not have an ID set, the tools should try to # complete the registration. flexmock(RegistrationHelper).should_receive('appscale_has_deployment_id')\ .and_return(False) appscale.register(deployment['deployment_id'])
def test_get_nodes(self): appscale = flexmock(AppScale()) builtin = flexmock(sys.modules['__builtin__']) builtin.should_call('open') nodes = {'node_info': [{'public_ip': 'blarg'}]} appscale_yaml = {'keyname': 'boo'} appscale.should_receive('get_locations_json_file').\ and_return('locations.json') # If the locations JSON file exists, it should return the locations as a # dictionary. builtin.should_receive('open').with_args('locations.json').\ and_return(flexmock(read=lambda: json.dumps(nodes))) self.assertEqual(nodes.get('node_info'), appscale.get_nodes(appscale_yaml['keyname'])) # If the locations JSON file does not exist, it should throw an # AppScaleException. builtin.should_receive('open').with_args('locations.json').\ and_raise(IOError) with self.assertRaises(AppScaleException): appscale.get_nodes(appscale_yaml['keyname'])
def main(): """ Execute appscale script. """ appscale = AppScale() if len(sys.argv) < 2: print(AppScale.USAGE) sys.exit(1) command = sys.argv[1] if command == "init": if len(sys.argv) < 2: cprint("Usage: appscale init [cloud | cluster]", 'red') print( "Specify 'cloud' for EC2, Eucalyptus, and Google Compute Engine " + "deployments, and 'cluster' if running over a virtualized cluster." ) sys.exit(1) try: environment = sys.argv[2] if len(sys.argv) == 3 else None appscale.init(environment) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) cprint( "AppScalefile successfully created! Be sure to " + "customize it for your particular cloud or cluster.", 'green') sys.exit(0) elif command == "up": update_dir = [] if len(sys.argv) > 2: if sys.argv[2] != '--update': cprint( "Usage: appscale up [--update] <code directory to update>", 'red') sys.exit(1) if len(sys.argv) < 4: cprint( "Usage: appscale up [--update] <code directory to update>", 'red') cprint("Please specify the code directory to update and build", 'red') update_dir = sys.argv[3:] try: appscale.up(update=update_dir) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "services": try: services.main() except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "ssh": if len(sys.argv) < 3: index = None else: index = sys.argv[2] try: appscale.ssh(index) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) except KeyboardInterrupt: # don't print the stack trace on a Control-C pass elif command == "stats": try: appscale.stats(sys.argv[2:]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "status": try: appscale.status(sys.argv[2:]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "deploy": try: if len(sys.argv) < 3 or len(sys.argv) > 5: cprint( "Usage: appscale deploy [--project <id>] <path to your app>", 'red') sys.exit(1) if len(sys.argv) == 3: appscale.deploy(sys.argv[2]) elif len(sys.argv) == 5: if sys.argv[2] != '--project': cprint( "Usage: appscale deploy [--project <id>] <path to your app>", 'red') sys.exit(1) appscale.deploy(sys.argv[4], sys.argv[3]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "create-user": try: if len(sys.argv) < 2 or len(sys.argv) > 3: cprint("Usage: appscale create-user [--admin]", 'red') sys.exit(1) if len(sys.argv) == 3: if sys.argv[2] == '--admin': appscale.create_user(True) else: cprint( "Error: Invalid argument to 'create-user' command. To create user as admin, " "you should specify the option '--admin'", 'red') cprint("Usage: appscale create-user --admin", 'red') sys.exit(1) elif len(sys.argv) == 2: appscale.create_user() except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "undeploy" or command == "remove": try: if len(sys.argv) != 3: cprint( "Usage: appscale {0} <path to your app>".format(command), 'red') sys.exit(1) appscale.undeploy(sys.argv[2]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "get": try: if len(sys.argv) != 3: cprint("Usage: appscale get <regex of properties to retrieve>", 'red') sys.exit(1) properties = appscale.get(sys.argv[2]) for property_name, property_value in sorted( properties.iteritems()): print "{0} -> {1}".format(property_name, property_value) sys.exit(0) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "set": try: if len(sys.argv) != 4: cprint("Usage: appscale set <property> <value>", 'red') sys.exit(1) appscale.set(sys.argv[2], sys.argv[3]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "tail": if len(sys.argv) < 3: # by default, tail the first node's logs, since that node is # typically the head node index = 0 else: index = sys.argv[2] if len(sys.argv) < 4: # by default, tail the AppController logs, since that's the # service we most often tail from regex = "controller*" else: regex = sys.argv[3] try: appscale.tail(index, regex) except KeyboardInterrupt: # don't print the stack trace on a Control-C pass except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "logs": if len(sys.argv) < 3: cprint("Usage: appscale logs <location to copy logs to>", 'red') sys.exit(1) try: appscale.logs(sys.argv[2], sys.argv[3:]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "destroy": cprint("Warning: destroy has been deprecated. Please use 'down'.", 'red') sys.exit(1) elif command == "clean": cprint( "Warning: clean has been deprecated. Please use 'down --clean'.", 'red') sys.exit(1) elif command == "down": if len(sys.argv) > 4: cprint("Usage: appscale down [--clean][--terminate]", 'red') sys.exit(1) to_clean = False to_terminate = False for index in range(2, len(sys.argv)): if sys.argv[index] == "--terminate": to_terminate = True elif sys.argv[index] == "--clean": to_clean = True else: cprint("Usage: appscale down [--clean][--terminate]", 'red') sys.exit(1) try: appscale.down(clean=to_clean, terminate=to_terminate) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "relocate": if len(sys.argv) != 5: cprint("Usage: appscale relocate appid http_port https_port", 'red') sys.exit(1) try: appscale.relocate(sys.argv[2], sys.argv[3], sys.argv[4]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "register": try: if len(sys.argv) != 3: cprint("Usage: appscale register <deployment ID>", "red") print("You can obtain a deployment ID from {0}".format( RegistrationHelper.ADD_DEPLOYMENT_URL)) sys.exit(1) appscale.register(sys.argv[2]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command in ["--version", "-v"]: print APPSCALE_VERSION sys.exit(0) else: print(AppScale.USAGE) if command == "help": sys.exit(0) else: sys.exit(1)
def main(): """ Execute appscale script. """ appscale = AppScale() if len(sys.argv) < 2: print(AppScale.USAGE) sys.exit(1) command = sys.argv[1] if command == "init": if len(sys.argv) < 2: cprint("Usage: appscale init [cloud | cluster]", 'red') print("Specify 'cloud' for EC2, Eucalyptus, and Google Compute Engine " + "deployments, and 'cluster' if running over a virtualized cluster.") sys.exit(1) try: environment = sys.argv[2] if len(sys.argv) == 3 else None appscale.init(environment) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) cprint("AppScalefile successfully created! Be sure to " + "customize it for your particular cloud or cluster.", 'green') sys.exit(0) elif command == "up": try: appscale.up() except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "services": try: services.main() except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "ssh": if len(sys.argv) < 3: index = None else: index = sys.argv[2] try: appscale.ssh(index) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) except KeyboardInterrupt: # don't print the stack trace on a Control-C pass elif command == "stats": try: appscale.stats(sys.argv[2:]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "status": try: appscale.status(sys.argv[2:]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "deploy": try: if len(sys.argv) < 3 or len(sys.argv) > 5: cprint("Usage: appscale deploy [--project <id>] <path to your app>", 'red') sys.exit(1) if len(sys.argv) == 3: appscale.deploy(sys.argv[2]) elif len(sys.argv) == 5: if sys.argv[2] != '--project': cprint("Usage: appscale deploy [--project <id>] <path to your app>", 'red') sys.exit(1) appscale.deploy(sys.argv[4], sys.argv[3]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "create-user": try: if len(sys.argv) < 2 or len(sys.argv) > 3: cprint("Usage: appscale create-user [--admin]", 'red') sys.exit(1) if len(sys.argv) == 3: if sys.argv[2] == '--admin': appscale.create_user(True) else: cprint("Error: Invalid argument to 'create-user' command. To create user as admin, " "you should specify the option '--admin'", 'red') cprint("Usage: appscale create-user --admin", 'red') sys.exit(1) elif len(sys.argv) == 2: appscale.create_user() except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "undeploy" or command == "remove": try: if len(sys.argv) != 3: cprint("Usage: appscale {0} <path to your app>".format(command), 'red') sys.exit(1) appscale.undeploy(sys.argv[2]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "get": try: if len(sys.argv) != 3: cprint("Usage: appscale get <regex of properties to retrieve>", 'red') sys.exit(1) properties = appscale.get(sys.argv[2]) for property_name, property_value in sorted(properties.iteritems()): print "{0} -> {1}".format(property_name, property_value) sys.exit(0) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "set": try: if len(sys.argv) != 4: cprint("Usage: appscale set <property> <value>", 'red') sys.exit(1) appscale.set(sys.argv[2], sys.argv[3]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "tail": if len(sys.argv) < 3: # by default, tail the first node's logs, since that node is # typically the head node index = 0 else: index = sys.argv[2] if len(sys.argv) < 4: # by default, tail the AppController logs, since that's the # service we most often tail from regex = "controller*" else: regex = sys.argv[3] try: appscale.tail(index, regex) except KeyboardInterrupt: # don't print the stack trace on a Control-C pass except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "logs": if len(sys.argv) < 3: cprint("Usage: appscale logs <location to copy logs to>", 'red') sys.exit(1) try: appscale.logs(sys.argv[2], sys.argv[3:]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "destroy": cprint("Warning: destroy has been deprecated. Please use 'down'.", 'red') sys.exit(1) elif command == "clean": cprint("Warning: clean has been deprecated. Please use 'down --clean'.", 'red') sys.exit(1) elif command == "down": if len(sys.argv) > 4: cprint("Usage: appscale down [--clean][--terminate]", 'red') sys.exit(1) to_clean = False to_terminate = False for index in range(2, len(sys.argv)): if sys.argv[index] == "--terminate": to_terminate = True elif sys.argv[index] == "--clean": to_clean = True else: cprint("Usage: appscale down [--clean][--terminate]", 'red') sys.exit(1) try: appscale.down(clean=to_clean, terminate=to_terminate) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "relocate": if len(sys.argv) != 5: cprint("Usage: appscale relocate appid http_port https_port", 'red') sys.exit(1) try: appscale.relocate(sys.argv[2], sys.argv[3], sys.argv[4]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command == "register": try: if len(sys.argv) != 3: cprint("Usage: appscale register <deployment ID>", "red") print("You can obtain a deployment ID from {0}" .format(RegistrationHelper.ADD_DEPLOYMENT_URL)) sys.exit(1) appscale.register(sys.argv[2]) except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) elif command in ["--version", "-v"]: print APPSCALE_VERSION sys.exit(0) elif command == "upgrade": try: appscale.upgrade() except Exception as exception: LocalState.generate_crash_log(exception, traceback.format_exc()) sys.exit(1) else: print(AppScale.USAGE) if command == "help": sys.exit(0) else: sys.exit(1)
def testUpWithNoAppScalefile(self): # calling 'appscale up' if there is no AppScalefile present # should throw up and die appscale = AppScale() self.addMockForNoAppScalefile(appscale) self.assertRaises(AppScalefileException, appscale.up)
def testSshWithNotIntArg(self): # calling 'appscale ssh not-int' should throw up and die appscale = AppScale() self.addMockForAppScalefile(appscale, "") self.assertRaises(TypeError, appscale.ssh, "boo")
def testCreateUserWithNoAppScalefile(self): # calling 'appscale create-user' with no AppScalefile in the local # directory should throw up and die appscale = AppScale() self.addMockForNoAppScalefile(appscale) self.assertRaises(AppScalefileException, appscale.create_user)
def testTailWithNotIntArg(self): # calling 'appscale tail not-int *' should throw up and die appscale = AppScale() self.addMockForAppScalefile(appscale, "") self.assertRaises(TypeError, appscale.tail, "boo", "")
def testSetPropertyWithNoAppScalefile(self): # calling 'appscale set' with no AppScalefile in the local directory # should throw up and die appscale = AppScale() self.addMockForNoAppScalefile(appscale) self.assertRaises(AppScalefileException, appscale.set, 'key', 'value')
def testDownWithNoAppScalefile(self): # calling 'appscale down' with no AppScalefile in the local # directory should throw up and die appscale = AppScale() self.addMockForNoAppScalefile(appscale) self.assertRaises(AppScalefileException, appscale.down)