def test_list_applications(monkeypatch): context = Context({'region': 'caprica', 'vpc': 'myvpc'}) security_group = MagicMock() security_group.tags = { 'Manifest': yaml.dump({ 'application_name': 'myapp', 'team_name': 'MyTeam', 'exposed_ports': [123] }) } context.get_applications = lambda: [Application('myapp', security_group)] context_constructor = lambda x, y: context monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() with runner.isolated_filesystem(): context.write_config('config.yaml') result = runner.invoke( cli, ['-p', 'default', '--config-file', 'config.yaml', 'app'], catch_exceptions=False) lines = result.output.splitlines() assert lines[1].split() == ['myapp', 'MyTeam', '[123]']
def test_delete_application(monkeypatch): monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock()) monkeypatch.setattr('boto.iam.connect_to_region', MagicMock()) context = Context({'region': 'caprica', 'vpc': 'myvpc'}) security_group = MagicMock() security_group.tags = { 'Manifest': yaml.dump({'application_name': 'myapp'}) } context.get_application = lambda name: Application('myapp', security_group) context.get_security_group = lambda name: None context_constructor = lambda x, y: context monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() with runner.isolated_filesystem(): context.write_config('config.yaml') result = runner.invoke(cli, [ '-p', 'default', '--config-file', 'config.yaml', 'app', 'delete', 'myapp' ], catch_exceptions=False)
def test_create_application(monkeypatch): monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock()) monkeypatch.setattr('boto.iam.connect_to_region', MagicMock()) monkeypatch.setattr('time.sleep', lambda s: s) context = Context({'region': 'caprica', 'vpc': 'myvpc'}) context.get_application = raise_application_not_found context_constructor = lambda x, y: context monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() data = { 'application_name': 'myapp', 'team_name': 'MyTeam', 'exposed_ports': [123] } with runner.isolated_filesystem(): with open('myapp.yaml', 'w') as fd: yaml.dump(data, fd) context.write_config('config.yaml') result = runner.invoke(cli, [ '-p', 'default', '--config-file', 'config.yaml', 'applications', 'create', 'myapp.yaml' ], catch_exceptions=False) assert 'Creating IAM role and instance profile.. OK' in result.output
def test_versions_create_https(monkeypatch): subnet = MagicMock() subnet.id = 'subnet-mysubnet' vpc_conn = MagicMock() vpc_conn.get_all_subnets = lambda x: [subnet] monkeypatch.setattr('boto.vpc.connect_to_region', vpc_conn) monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock()) monkeypatch.setattr('boto.route53.connect_to_region', MagicMock()) monkeypatch.setattr('boto.ec2.autoscale.connect_to_region', MagicMock()) monkeypatch.setattr('boto.ec2.elb.connect_to_region', MagicMock()) monkeypatch.setattr('time.sleep', lambda s: s) monkeypatch.setattr('aws_minion.cli.map_subnets', lambda s, r: {'public': [subnet], 'shared': [], 'private': []}) monkeypatch.setattr('aws_minion.cli.docker_image_exists', lambda i: True) security_group = MagicMock() security_group.tags = {'Manifest': json.dumps({'exposed_ports': [8080], 'team_name': 'MyTeam'})} security_groups = {'app-myapp': security_group, 'app-myapp-lb': MagicMock()} auto_scaling_group = MagicMock() auto_scaling_group.tags = [MagicMock(key='DockerImage', value='foo/bar:123')] auto_scaling_group.desired_capacity = 3 app = Application('myapp', security_group) version = ApplicationVersion('myregion', 'myapp', '1.0', auto_scaling_group) version.weight = 120 context = Context({'region': 'caprica', 'vpc': 'myvpc', 'loggly_auth_token': 'abc', 'domain': 'mydomain', 'ssl_certificate_arn': 'super secret'}) context.get_versions = lambda: [version] context.get_application = lambda x: app context.get_security_group = lambda x: security_groups.get(x) context.get_vpc_config = lambda: {'nameservers': ['8.8.8.8'], 'cacerts': ['https://example.org/cacert.pem'], 'registry': 'example.org', 'registry_insecure': True} context_constructor = lambda x, y: context monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() with runner.isolated_filesystem(): context.write_config('config.yaml') result = runner.invoke(cli, ['-p', 'default', '--config-file', 'config.yaml', 'versions', 'create', 'myapp', '1.0', 'mydocker:2.3', '-e', 'MY_ENV_VAR=123'], catch_exceptions=False) assert 'ABORTED. Default health check time to wait for members to become active has been exceeded.' in result.output
def test_versions_delete(monkeypatch): instances = [MagicMock(state='TERMINATED', id='instance-1')] conn = MagicMock(get_only_instances=lambda instance_ids: instances) monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock(return_value=conn)) monkeypatch.setattr('boto.route53.connect_to_region', MagicMock()) monkeypatch.setattr('boto.ec2.autoscale.connect_to_region', MagicMock()) monkeypatch.setattr('boto.ec2.elb.connect_to_region', MagicMock()) monkeypatch.setattr('time.sleep', lambda s: s) security_group = MagicMock() security_group.tags = {'Manifest': json.dumps({'exposed_ports': [8080], 'team_name': 'MyTeam'})} auto_scaling_group = MagicMock() auto_scaling_group.tags = [MagicMock(key='DockerImage', value='foo/bar:123')] auto_scaling_group.instances = [MagicMock(instance_id='instance-1')] app = Application('myapp', security_group) version = ApplicationVersion('myregion', 'myapp', '1.0', auto_scaling_group) version.weight = 120 context = Context({'region': 'caprica', 'vpc': 'myvpc', 'domain': 'mydomain'}) context.get_versions = lambda a, b=None: [version] context.get_application = lambda x: app context_constructor = lambda x, y: context monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() with runner.isolated_filesystem(): context.write_config('config.yaml') result = runner.invoke(cli, ['-p', 'default', '--config-file', 'config.yaml', 'versions', 'delete', 'myapp', '1.0'], catch_exceptions=False) assert 'Deleting load balancer.. OK' in result.output
def test_get_instances(monkeypatch): conn = MagicMock(name='conn') instance = MagicMock(name='instance') instance.tags = {'Name': 'app-myapp-123'} instance.vpc_id = 'myvpc' instance.id = 'myid' conn.get_only_instances.return_value = [instance] monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock(name='connect_to_region', return_value=conn)) ctx = Context({ 'region': 'someregion', 'domain': 'apps.example.com', 'vpc': 'myvpc' }) instances = ctx.get_instances() assert len(instances) == 1 instance = ctx.get_instance_by_id('myid') assert instance.tags == instances[0].tags assert ctx.get_instance_by_id('000') is None
def test_get_applications(monkeypatch): conn = MagicMock(name='conn') sg1 = MagicMock(name='invalid sg') sg2 = MagicMock(name='valid sg') sg2.name = 'app-myapp' sg2.tags = {'Manifest': 'a: b'} sg2.vpc_id = 'myvpc' sg3 = MagicMock(name='another invalid sg') sg3.name = 'app-myapp-db' sg3.vpc_id = 'myvpc' conn.get_all_security_groups.return_value = [sg1, sg2, sg3] monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock(name='connect_to_region', return_value=conn)) ctx = Context({ 'region': 'someregion', 'domain': 'apps.example.com', 'vpc': 'myvpc' }) apps = ctx.get_applications() assert len(apps) == 1 app = ctx.get_application('myapp') assert app == apps[0]
def test_get_versions(monkeypatch): record = MagicMock() record.type = 'CNAME' record.identifier = 'app-myapp' record.weight = 100 zone = MagicMock(name='zone') zone.get_records.return_value = [record] dns_conn = MagicMock(name='dns_conn') dns_conn.get_zone.return_value = zone group = MagicMock(name='auto scale group') group.name = 'app-myapp-1.0' autoscale = MagicMock(name='autoscale_conn') autoscale.get_all_groups.return_value = [group] monkeypatch.setattr('boto.ec2.autoscale.connect_to_region', MagicMock(return_value=autoscale)) monkeypatch.setattr('boto.route53.connect_to_region', MagicMock(return_value=dns_conn)) ctx = Context({'region': 'someregion', 'domain': 'apps.example.com'}) versions = ctx.get_versions('myapp', '0.1') assert versions == [] versions = ctx.get_versions('myapp', '1.0') assert len(versions) == 1 assert versions[0].application_name == 'myapp' assert versions[0].version == '1.0' version = ctx.get_version('myapp', '1.0') assert version == versions[0] with pytest.raises(Exception): ctx.get_version('non-existing-app', '0.1')
def test_versions_list(monkeypatch): auto_scaling_group = MagicMock() auto_scaling_group.tags = [MagicMock(key='DockerImage', value='foo/bar:123')] auto_scaling_group.desired_capacity = 3 version = ApplicationVersion('myregion', 'myapp', '1.0', auto_scaling_group) version.weight = 120 context = Context({'region': 'caprica'}) context.get_versions = lambda: [version] context.get_vpc_config = lambda: {} context_constructor = lambda x, y: context monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() with runner.isolated_filesystem(): context.write_config('config.yaml') result = runner.invoke(cli, ['-p', 'default', '--config-file', 'config.yaml', 'versions'], catch_exceptions=False) lines = result.output.splitlines() cols = lines[1].split() assert cols == ['myapp', '1.0', 'foo/bar:123', '(no', 'instances)', '3', '60.0']
def test_versions_traffic(monkeypatch): monkeypatch.setattr('boto.vpc.connect_to_region', MagicMock()) monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock()) monkeypatch.setattr('boto.ec2.autoscale.connect_to_region', MagicMock()) monkeypatch.setattr('boto.ec2.elb.connect_to_region', MagicMock()) monkeypatch.setattr('time.sleep', lambda s: s) security_group = MagicMock() security_group.tags = {'Manifest': json.dumps({'exposed_ports': [8080], 'team_name': 'MyTeam'})} security_groups = {'app-myapp': security_group, 'app-myapp-lb': MagicMock()} auto_scaling_group = MagicMock() auto_scaling_group.tags = [MagicMock(key='DockerImage', value='foo/bar:123')] auto_scaling_group.desired_capacity = 3 app = Application('myapp', security_group) # start creating mocking of the route53 record sets and Application Versions # this is a lot of dirty and nasty code. Please, somebody help this code. versions = [ApplicationVersion('myregion', 'myapp', '1.0', auto_scaling_group), ApplicationVersion('myregion', 'myapp', '2.0', auto_scaling_group), ApplicationVersion('myregion', 'myapp', '3.0', auto_scaling_group), ApplicationVersion('myregion', 'myapp', '4.0', auto_scaling_group), ] versions[0].weight = 60 * PERCENT_RESOLUTION versions[1].weight = 30 * PERCENT_RESOLUTION versions[2].weight = 10 * PERCENT_RESOLUTION versions[3].weight = 0 r53conn = Mock(name='r53conn') rr = MagicMock() records = collections.OrderedDict((versions[i].dns_identifier, MagicMock(weight=versions[i].weight, identifier=versions[i].dns_identifier )) for i in (0, 1, 2, 3)) rr.__iter__ = lambda x: iter(records.values()) for r in rr: r.name = "myapp.example.org." r.type = "CNAME" def add_change(op, dns_name, rtype, ttl, identifier, weight): if op == 'CREATE': x = MagicMock(weight=weight, identifier=identifier) x.name = "myapp.example.org" x.type = "CNAME" records[identifier] = x return Mock(name='change') def add_change_record(op, record): if op == 'DELETE': records[record.identifier].weight = 0 elif op == 'USPERT': assert records[record.identifier].weight == record.weight rr.add_change = add_change rr.add_change_record = add_change_record r53conn().get_zone().get_records.return_value = rr monkeypatch.setattr('boto.route53.connect_to_region', r53conn) context = Context({'region': 'caprica', 'vpc': 'myvpc', 'loggly_auth_token': 'abc', 'domain': 'example.org'}) context.get_versions = lambda v=None: versions context.get_application = lambda x: app context.get_security_group = lambda x: security_groups.get(x) context_constructor = Mock(return_value=context) monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() common_opts = ['-p', 'default', '--config-file', 'config.yaml', 'versions', 'traffic', 'myapp'] def run(opts): return runner.invoke(cli, common_opts + opts, catch_exceptions=False) with runner.isolated_filesystem(): context.write_config('config.yaml') run(['4.0', '100']) ri = iter(rr) assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 200 run(['3.0', '10']) ri = iter(rr) assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 20 assert next(ri).weight == 180 run(['2.0', '0.5']) ri = iter(rr) assert next(ri).weight == 0 assert next(ri).weight == 1 assert next(ri).weight == 20 assert next(ri).weight == 179 run(['1.0', '1']) ri = iter(rr) assert next(ri).weight == 2 assert next(ri).weight == 1 assert next(ri).weight == 19 assert next(ri).weight == 178 run(['4.0', '95']) ri = iter(rr) assert next(ri).weight == 1 assert next(ri).weight == 1 assert next(ri).weight == 13 assert next(ri).weight == 185 run(['4.0', '100']) ri = iter(rr) assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 200 run(['4.0', '10']) ri = iter(rr) assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 200 run(['4.0', '0']) ri = iter(rr) assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 0 assert next(ri).weight == 0
def test_create_application(monkeypatch): monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock()) monkeypatch.setattr('boto.iam.connect_to_region', MagicMock()) monkeypatch.setattr('time.sleep', lambda s: s) mock_sgr = MagicMock() monkeypatch.setattr('aws_minion.cli.SecurityGroupRule', mock_sgr) context = Context({'region': 'caprica', 'vpc': 'myvpc'}) context.get_application = raise_application_not_found context_constructor = lambda x, y: context monkeypatch.setattr('aws_minion.cli.Context', context_constructor) runner = CliRunner() data = { 'application_name': 'myapp', 'team_name': 'MyTeam', 'exposed_ports': [123], 'exposed_protocol': 'http' } mock_sgr.reset_mock() with runner.isolated_filesystem(): with open('myapp.yaml', 'w') as fd: yaml.dump(data, fd) context.write_config('config.yaml') result = runner.invoke(cli, [ '-p', 'default', '--config-file', 'config.yaml', 'applications', 'create', 'myapp.yaml' ], catch_exceptions=False) assert call('tcp', 80, 80, '0.0.0.0/0', None) in mock_sgr.call_args_list assert call('tcp', 443, 443, '0.0.0.0/0', None) in mock_sgr.call_args_list assert 'Creating IAM role and instance profile.. OK' in result.output data_tcp = { 'application_name': 'myapp', 'team_name': 'MyTeam', 'exposed_ports': [123], 'exposed_protocol': 'tcp' } mock_sgr.reset_mock() with runner.isolated_filesystem(): with open('myapp.yaml', 'w') as fd: yaml.dump(data_tcp, fd) context.write_config('config.yaml') result = runner.invoke(cli, [ '-p', 'default', '--config-file', 'config.yaml', 'applications', 'create', 'myapp.yaml' ], catch_exceptions=False) assert mock_sgr.call_args == call('tcp', 123, 123, None, 'app-myapp-lb') assert 'Creating IAM role and instance profile.. OK' in result.output
def test_get_application_not_found(monkeypatch): monkeypatch.setattr('boto.ec2.connect_to_region', MagicMock()) ctx = Context({'region': 'someregion'}) with pytest.raises(ApplicationNotFound): ctx.get_application('myapp-non-existing')