def push(tag, force, overwrite): if force is None and shout('git status --porcelain'): raise HokusaiError("Working directory is not clean. Aborting.") if force is None and shout('git status --porcelain --ignored'): raise HokusaiError("Working directory contains ignored files and/or directories. Aborting.") ecr = ECR() if not ecr.project_repository_exists(): raise HokusaiError("ECR repository %s does not exist... did you run `hokusai setup` for this project?" % config.project_name) shout(ecr.get_login()) if tag is None: tag = shout('git rev-parse HEAD').strip() if overwrite is None and ecr.tag_exists(tag): raise HokusaiError("Tag %s already exists in remote repository. Aborting." % tag) docker_compose_yml = os.path.join(os.getcwd(), 'hokusai/common.yml') shout("docker-compose -f %s -p hokusai build" % docker_compose_yml, print_output=True) build = "hokusai_%s:latest" % config.project_name shout("docker tag %s %s:%s" % (build, config.aws_ecr_registry, tag)) shout("docker push %s:%s" % (config.aws_ecr_registry, tag), print_output=True) print_green("Pushed %s to %s:%s" % (build, config.aws_ecr_registry, tag)) shout("docker tag %s %s:%s" % (build, config.aws_ecr_registry, 'latest')) shout("docker push %s:%s" % (config.aws_ecr_registry, 'latest'), print_output=True) print_green("Pushed %s to %s:%s" % (build, config.aws_ecr_registry, 'latest'))
class TestECR(HokusaiIntegrationTestCase): def setUp(self): self.ecr = ECR() @httpretty.activate def test_registry(self): httpretty.register_uri(httpretty.POST, "https://ecr.us-east-1.amazonaws.com/", body=open(os.path.join(os.getcwd(), 'test', 'fixtures', 'ecr-repositories-response.json')).read(), content_type="application/x-amz-json-1.1") repositories = [str(repo['repositoryName']) for repo in self.ecr.registry()] self.assertTrue('foo' in repositories) self.assertTrue('bar' in repositories) self.assertTrue('baz' in repositories) @httpretty.activate def test_project_repository_exists(self): httpretty.register_uri(httpretty.POST, "https://ecr.us-east-1.amazonaws.com/", body=open(os.path.join(os.getcwd(), 'test', 'fixtures', 'ecr-repositories-response.json')).read(), content_type="application/x-amz-json-1.1") self.assertTrue(self.ecr.project_repository_exists()) @httpretty.activate def test_create_project_repository(self): httpretty.register_uri(httpretty.POST, "https://ecr.us-east-1.amazonaws.com/", body=open(os.path.join(os.getcwd(), 'test', 'fixtures', 'ecr-create-repository-response.json')).read(), content_type="application/x-amz-json-1.1") self.assertTrue(self.ecr.create_project_repository()) @httpretty.activate def test_get_login(self): httpretty.register_uri(httpretty.POST, "https://ecr.us-east-1.amazonaws.com/", body=open(os.path.join(os.getcwd(), 'test', 'fixtures', 'ecr-authorization-response.json')).read(), content_type="application/x-amz-json-1.1") self.assertEqual(self.ecr.get_login(), 'docker login -u AWS -p 76W8YEUFHDSAE98DFDHSFSDFIUHSDAJKGKSADFGKDF https://123456789012.dkr.ecr.us-east-1.amazonaws.com') @httpretty.activate def test_get_images(self): httpretty.register_uri(httpretty.POST, "https://ecr.us-east-1.amazonaws.com/", body=open(os.path.join(os.getcwd(), 'test', 'fixtures', 'ecr-images-response.json')).read(), content_type="application/x-amz-json-1.1") self.assertEqual(self.ecr.get_images()[0]['imageTags'], ['7shdn4f0f34bb8shdkb313cbeccb2fc031808duho', 'latest']) self.assertEqual(self.ecr.get_images()[0]['imageDigest'], 'sha256:8sh968hsn205e8bff53ba8ed1006c7f41dacd17db164efdn6d346204f997shdn') self.assertEqual(self.ecr.get_images()[0]['registryId'], '123456789012') self.assertEqual(self.ecr.get_images()[0]['repositoryName'], 'foo') @httpretty.activate def test_tag_exists(self): httpretty.register_uri(httpretty.POST, "https://ecr.us-east-1.amazonaws.com/", body=open(os.path.join(os.getcwd(), 'test', 'fixtures', 'ecr-images-response.json')).read(), content_type="application/x-amz-json-1.1") self.assertTrue(self.ecr.tag_exists('7shdn4f0f34bb8shdkb313cbeccb2fc031808duho')) self.assertTrue(self.ecr.tag_exists('latest'))
def environment_create(context): kubernetes_yml = os.path.join(os.getcwd(), "hokusai/%s.yml" % context) if not os.path.isfile(kubernetes_yml): raise HokusaiError("Yaml file %s does not exist for given context." % kubernetes_yml) ecr = ECR() if not ecr.project_repository_exists(): raise HokusaiError( "ECR repository %s does not exist... did you run `hokusai setup` for this project?" % config.project_name) if not ecr.tag_exists('latest'): raise HokusaiError( "Image tag 'latest' does not exist... did you run `hokusai push`?") if not ecr.tag_exists(context): ecr.retag('latest', context) print_green("Updated tag 'latest' -> %s" % context) kctl = Kubectl(context) shout(kctl.command("create --save-config -f %s" % kubernetes_yml), print_output=True) print_green("Created remote environment %s" % context)
def check(): return_code = 0 def check_ok(check_item): print_green(u'\u2714 ' + check_item + ' found') def check_err(check_item): print_red(u'\u2718 ' + check_item + ' not found') config.check() try: shout('docker --version') check_ok('docker') except CalledProcessError: check_err('docker') return_code += 1 try: shout('docker-compose --version') check_ok('docker-compose') except CalledProcessError: check_err('docker-compose') return_code += 1 try: shout('kubectl version') check_ok('kubectl') except CalledProcessError: check_err('kubectl') return_code += 1 try: shout('git version') check_ok('git') except CalledProcessError: check_err('git') return_code += 1 if os.environ.get('AWS_ACCESS_KEY_ID') is not None: check_ok('$AWS_ACCESS_KEY_ID') else: check_err('$AWS_ACCESS_KEY_ID') return_code += 1 if os.environ.get('AWS_SECRET_ACCESS_KEY') is not None: check_ok('$AWS_SECRET_ACCESS_KEY') else: check_err('$AWS_SECRET_ACCESS_KEY') return_code += 1 ecr = ECR() if ecr.project_repository_exists(): check_ok("ECR repository '%s'" % config.project_name) else: check_err("ECR repository '%s'" % config.project_name) return_code += 1 if os.path.isfile(os.path.join(os.getcwd(), 'hokusai/common.yml')): check_ok('./hokusai/common.yml') else: check_err('./hokusai/common.yml') return_code += 1 if os.path.isfile(os.path.join(os.getcwd(), 'hokusai/development.yml')): check_ok('./hokusai/development.yml') else: check_err('./hokusai/development.yml') return_code += 1 if os.path.isfile(os.path.join(os.getcwd(), 'hokusai/test.yml')): check_ok('./hokusai/test.yml') else: check_err('./hokusai/test.yml') return_code += 1 for context in ['staging', 'production']: if context in Kubectl('staging').contexts(): check_ok("kubectl context '%s'" % context) else: check_err("kubectl context '%s'" % context) return_code += 1 if os.path.isfile(os.path.join(os.getcwd(), "hokusai/%s.yml" % context)): check_ok("./hokusai/%s.yml" % context) else: check_err("./hokusai/%s.yml" % context) return_code += 1 return return_code
def setup(aws_account_id, project_type, project_name, aws_ecr_region, port, internal): mkpath(os.path.join(os.getcwd(), 'hokusai')) config.create(project_name.lower().replace('_', '-'), aws_account_id, aws_ecr_region) if project_type == 'ruby-rack': dockerfile = env.get_template("Dockerfile-ruby.j2") base_image = 'ruby:latest' run_command = 'bundle exec rackup' development_command = 'bundle exec rackup' test_command = 'bundle exec rake' runtime_environment = { 'development': ["RACK_ENV=development"], 'test': ["RACK_ENV=test"], 'production': [{'name': 'RACK_ENV', 'value': 'production'}] } elif project_type == 'ruby-rails': dockerfile = env.get_template("Dockerfile-rails.j2") base_image = 'ruby:latest' run_command = 'bundle exec rails server' development_command = 'bundle exec rails server' test_command = 'bundle exec rake' runtime_environment = { 'development': ["RAILS_ENV=development"], 'test': ["RAILS_ENV=test"], 'production': [{'name': 'RAILS_ENV', 'value': 'production'}, {'name': 'RAILS_SERVE_STATIC_FILES', 'value': 'true'}, {'name': 'RAILS_LOG_TO_STDOUT', 'value': 'true'}] } elif project_type == 'nodejs': dockerfile = env.get_template("Dockerfile-node.j2") base_image = 'node:latest' run_command = 'node index.js' development_command = 'node index.js' test_command = 'npm test' runtime_environment = { 'development': ["NODE_ENV=development"], 'test': ["NODE_ENV=test"], 'production': [{'name': 'NODE_ENV', 'value': 'production'}] } elif project_type == 'elixir': dockerfile = env.get_template("Dockerfile-elixir.j2") base_image = 'elixir:latest' run_command = 'mix run --no-halt' development_command = 'mix run' test_command = 'mix test' runtime_environment = { 'development': ["MIX_ENV=dev"], 'test': ["MIX_ENV=test"], 'production': [{'name': 'MIX_ENV', 'value': 'prod'}] } elif project_type == 'python-wsgi': dockerfile = env.get_template("Dockerfile-python.j2") base_image = 'python:latest' run_command = "gunicorn -b 0.0.0.0:%s app" % port development_command = "python -m werkzeug.serving -b 0.0.0.0:%s %s" % (port, project_name) test_command = 'python -m unittest discover .' runtime_environment = { 'development': ["CONFIG_FILE=config/development.py"], 'test': ["CONFIG_FILE=config/test.py"], 'production': [{'name': 'CONFIG_FILE', 'value': 'config/production.py'}] } with open(os.path.join(os.getcwd(), 'Dockerfile'), 'w') as f: f.write(dockerfile.render(base_image=base_image, command=run_command, target_port=port)) with open(os.path.join(os.getcwd(), 'hokusai', "common.yml"), 'w') as f: services = { config.project_name: { 'build': { 'context': '../' } } } data = OrderedDict([ ('version', '2'), ('services', services) ]) payload = YAML_HEADER + yaml.safe_dump(data, default_flow_style=False) f.write(payload) for compose_environment in ['development', 'test']: with open(os.path.join(os.getcwd(), 'hokusai', "%s.yml" % compose_environment), 'w') as f: services = { config.project_name: { 'extends': { 'file': 'common.yml', 'service': config.project_name } } } if compose_environment == 'development': services[config.project_name]['command'] = development_command services[config.project_name]['ports'] = ["%s:%s" % (port, port)] services[config.project_name]['volumes'] = ['../:/app'] if compose_environment == 'test': services[config.project_name]['command'] = test_command services[config.project_name]['environment'] = runtime_environment[compose_environment] data = OrderedDict([ ('version', '2'), ('services', services) ]) payload = YAML_HEADER + yaml.safe_dump(data, default_flow_style=False) f.write(payload) for remote_environment in ['staging', 'production']: with open(os.path.join(os.getcwd(), 'hokusai', "%s.yml" % remote_environment), 'w') as f: if remote_environment == 'production': replicas = 2 else: replicas = 1 deployment_data = build_deployment(config.project_name, "%s:%s" % (config.aws_ecr_registry, remote_environment), port, environment=runtime_environment['production'], always_pull=True, replicas=replicas) service_data = build_service(config.project_name, port, target_port=port, internal=internal) remote_environment_yaml = deployment_data + service_data f.write(remote_environment_yaml) print_green("Config created in ./hokusai") ecr = ECR() if ecr.project_repository_exists(): print_green("ECR repository %s found. Skipping creation." % config.project_name) return 0 if ecr.create_project_repository(): print_green("Created ECR repository %s" % config.project_name) return 0 else: raise HokusaiError("Could not create ECR repository %s - check your credentials." % config.project_name)