def test_purge(lxd_client_cls): # Application context app = get_test_application() job = { "_id": "test_job_id", "app_id": "test_app_id", "command": "buildimage", "instance_type": "test_instance_type", "options": [False] # Do not skip bootstrap } test_config = get_test_config(ami_retention=3) # Mocks lxd_client = mock.MagicMock() lxd_client_cls.return_value = lxd_client lxd_image = mock.MagicMock() lxd_client.images.all.return_value = [lxd_image for i in range(0, 6)] # Purge images with mock.patch('ghost_tools.config', new=test_config): image_builder = LXDImageBuilder(app, job, None, LOG_FILE, test_config) image_builder.purge_old_images() # Test assert lxd_image.delete.call_count == 3
def test_build_image_custom_envvars(packer_run_packer_cmd, provisioner_get_local_repo_path): # Application context app = get_test_application(env_vars=[{ "var_value": u"hello world !", "var_key": "TESTVAR" }, { "var_value": u"ên français avec des accents! héhé Ã@¤.", "var_key": "C_USTom2" }]) job = { "_id": "test_job_id", "app_id": "test_app_id", "command": "buildimage", "instance_type": "test_instance_type", "options": [False] # Do not skip bootstrap } test_config = get_test_config() # Mocks packer_run_packer_cmd.return_value = (0, "something:test_ami_id") tmp_dir = tempfile.mkdtemp() provisioner_get_local_repo_path.return_value = tmp_dir # Build image with mock.patch('ghost_tools.config', new=test_config): image_builder = AWSImageBuilder(app, job, None, LOG_FILE, test_config) ami_id, ami_name = image_builder.start_builder() # Test assert ami_id == "test_ami_id" assert ami_name.startswith("ami.test.eu-west-1.webfront.test-app.") with open(os.path.join(PACKER_JSON_PATH, job['_id'], 'aws_builder.json'), 'r') as f: # Verify packer config packer_config = json.load(f) packer_config_reference = { "provisioners": [{ "type": "shell", "environment_vars": [ u"C_USTom2=\u00ean fran\u00e7ais avec des accents! h\u00e9h\u00e9 \u00c3@\u00a4.", "GHOST_APP=test-app", "GHOST_ENV=test", "GHOST_ENV_COLOR=", "GHOST_ROLE=webfront", "TESTVAR=hello world !" ], "script": "/ghost/test-app/test/webfront/hook-pre_buildimage" }, { "skip_bootstrap": False, "log_level": "info", "local_state_tree": os.path.join(tmp_dir, 'salt'), "local_pillar_roots": os.path.join(tmp_dir, 'pillar'), "type": "salt-masterless" }, { "type": "shell", "environment_vars": [ u"C_USTom2=\u00ean fran\u00e7ais avec des accents! h\u00e9h\u00e9 \u00c3@\u00a4.", "GHOST_APP=test-app", "GHOST_ENV=test", "GHOST_ENV_COLOR=", "GHOST_ROLE=webfront", "TESTVAR=hello world !" ], "script": "/ghost/test-app/test/webfront/hook-post_buildimage" }, { "inline": [ "sudo rm -rf /srv/salt || echo 'Salt - no cleanup salt'", "sudo rm -rf /srv/pillar || echo 'Salt - no cleanup pillar'" ], "type": "shell" }], "builders": [{ "ami_block_device_mappings": [], "launch_block_device_mappings": [], "source_ami": "ami-source", "tags": { "Name": "ec2.name.test", "tag-name": "tag-value", }, "subnet_id": "subnet-test", "ssh_username": "******", "ssh_interface": "private_ip", "region": "eu-west-1", "security_group_ids": ["sg-test"], "ami_name": ami_name, "iam_instance_profile": "iam.profile.test", "instance_type": "test_instance_type", "associate_public_ip_address": True, "vpc_id": "vpc-test", "type": "amazon-ebs", "ssh_pty": True }] } assert packer_config == packer_config_reference
def test_build_image_ansible(packer_run_packer_cmd, gcall, provisioner_get_local_repo_path): # Application context app = get_test_application() job = { "_id": "test_job_id", "app_id": "test_app_id", "command": "buildimage", "instance_type": "test_instance_type", "options": [False] # Do not skip bootstrap } test_config = get_test_config( features_provisioners={ 'ansible': { 'git_revision': 'master', 'git_repo': 'my_ansible_repo', 'base_playbook_file': 'tests/provisioners_data/base_playbook.yml', 'base_playbook_requirements_file': 'tests/provisioners_data/base_requirements.yml', } }) del test_config['features_provisioners']['salt'] # Mocks packer_run_packer_cmd.return_value = (0, "something:test_ami_id") tmp_dir = tempfile.mkdtemp() venv_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '.tox/py27/bin/') shutil.copyfile( os.path.join(os.path.dirname(__file__), 'provisioners_data', 'requirements.yml'), os.path.join(tmp_dir, 'requirements.yml')) provisioner_get_local_repo_path.return_value = tmp_dir # Build image with mock.patch('ghost_tools.config', new=test_config): image_builder = AWSImageBuilder(app, job, None, LOG_FILE, test_config) ami_id, ami_name = image_builder.start_builder() # Test assert ami_id == "test_ami_id" assert ami_name.startswith("ami.test.eu-west-1.webfront.test-app.") gcall.assert_called_once_with( "{0}ansible-galaxy install -r {1}/requirement_app.yml -p {1}/roles". format(venv_dir, tmp_dir), 'Ansible - ansible-galaxy command', LOG_FILE) with open(os.path.join(PACKER_JSON_PATH, job['_id'], 'aws_builder.json'), 'r') as f: # Verify generated ansible files with open(os.path.join(tmp_dir, 'requirement_app.yml'), 'r') as f2: requirement_app = yaml.load(f2) assert requirement_app == [{ "src": "base-role-src", "version": "base-role-version" }, { "name": "feature-ansible", "scm": "test-scm", "src": "test-src", "version": "test-version" }] with open(os.path.join(tmp_dir, 'main.yml'), 'r') as f3: playbook = yaml.load(f3) assert playbook == [{ "name": "Base playbook", "hosts": "all", "roles": ['ansible-base-role'] }, { "name": "Ghost application features", "hosts": "all", "roles": [{ "role": "feature-ansible", "feature-property": "property" }] }] # Verify packer config packer_config = json.load(f) packer_config_reference = { "provisioners": [{ "type": "shell", "environment_vars": [ "EMPTY_ENV=", "GHOST_APP=test-app", "GHOST_ENV=test", "GHOST_ENV_COLOR=", "GHOST_ROLE=webfront", ], "script": "/ghost/test-app/test/webfront/hook-pre_buildimage" }, { "type": "ansible", "playbook_file": os.path.join(tmp_dir, "main.yml"), "ansible_env_vars": [ "ANSIBLE_HOST_KEY_CHECKING=False", "ANSIBLE_FORCE_COLOR=1", "PYTHONUNBUFFERED=1", "ANSIBLE_ROLES_PATH={}".format(tmp_dir) ], "user": "******", "command": os.path.join(venv_dir, "ansible-playbook"), "extra_arguments": ['-v'], }, { "type": "shell", "environment_vars": [ "EMPTY_ENV=", "GHOST_APP=test-app", "GHOST_ENV=test", "GHOST_ENV_COLOR=", "GHOST_ROLE=webfront", ], "script": "/ghost/test-app/test/webfront/hook-post_buildimage" }], "builders": [{ "ami_block_device_mappings": [], "launch_block_device_mappings": [], "source_ami": "ami-source", "tags": { "Name": "ec2.name.test", "tag-name": "tag-value", }, "subnet_id": "subnet-test", "ssh_username": "******", "ssh_interface": "private_ip", "region": "eu-west-1", "security_group_ids": ["sg-test"], "ami_name": ami_name, "iam_instance_profile": "iam.profile.test", "instance_type": "test_instance_type", "associate_public_ip_address": True, "vpc_id": "vpc-test", "type": "amazon-ebs", "ssh_pty": True }] } assert packer_config == packer_config_reference
def test_build_image(lxd_client_cls): # Application context app = get_test_application() job = { "_id": "test_job_id", "app_id": "test_app_id", "command": "buildimage", "instance_type": "test_instance_type", "options": [False] # Do not skip bootstrap } test_config = get_test_config( features_provisioners={ 'ansible': { 'git_revision': 'master', 'git_repo': 'my_ansible_repo', 'base_playbook_file': 'tests/provisioners_data/base_playbook.yml', 'base_playbook_requirements_file': 'tests/provisioners_data/base_requirements.yml', } }) # Mocks lxd_client = mock.MagicMock() lxd_client_cls.return_value = lxd_client lxd_containers_mock = lxd_client.containers lxd_profiles_mock = lxd_client.profiles lxd_container_mock = mock.MagicMock() lxd_client.containers.create.return_value = lxd_container_mock valid_execution_mock = mock.MagicMock() valid_execution_mock.exit_code = 0 valid_execution_mock.stdout = 'STDOUT' valid_execution_mock.stderr = 'STDERR' lxd_container_mock.execute.return_value = valid_execution_mock lxd_client.images.all.return_value = [] venv_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '.tox/py27') venv_bin_dir = os.path.join(venv_dir, 'bin') # Build image with mock.patch('ghost_tools.config', new=test_config): image_builder = LXDImageBuilder(app, job, None, LOG_FILE, test_config) image_builder.set_source_hooks('/source-hook-path') image_builder.start_builder() # Test container_name = image_builder._container_name assert container_name.startswith("ami-test-eu-west-1-webfront-test-app-") expected_container_config = { 'source': { "type": "image", "protocol": "lxd", "mode": "pull", "fingerprint": "lxd-container-image-test", "server": "http://lxd-image-endpoint:1234", }, 'config': { "security.privileged": 'True' }, 'ephemeral': False, 'name': container_name, 'profiles': ["default", container_name], } lxd_containers_mock.create.assert_called_once_with( expected_container_config, wait=True) lxd_container_mock.start.assert_called_once_with(wait=True) lxd_container_mock.stop.assert_called_once_with(wait=True) lxd_container_mock.execute.assert_any_call( ["sh", "/ghost/hook-pre_buildimage"], image_builder._get_ghost_env_vars()) lxd_container_mock.execute.assert_any_call( ["sh", "/ghost/hook-post_buildimage"], image_builder._get_ghost_env_vars()) lxd_container_mock.execute.assert_any_call([ os.path.join(venv_bin_dir, "ansible-playbook"), "-i", "localhost,", "--connection=local", "/srv/ansible/main.yml", "-v" ]) lxd_container_mock.execute.assert_any_call([ "salt-call", "state.highstate", "--file-root=/srv/salt/salt", "--pillar-root=/srv/salt/pillar", "--local", "-l", "info" ]) expected_devices_config = { 'venv': { 'path': venv_dir, 'source': venv_dir, 'type': 'disk', }, 'salt': { 'path': '/srv/salt', 'source': "/tmp/ghost-features-provisioner/salt-test_job_id", 'type': 'disk' }, 'ansible': { 'path': '/srv/ansible', 'source': "/tmp/ghost-features-provisioner/ansible-test_job_id", 'type': 'disk' }, 'hooks': { 'path': "/ghost", 'source': "/source-hook-path", 'type': 'disk' }, } lxd_profiles_mock.create.assert_called_once_with( container_name, devices=expected_devices_config) lxd_container_mock.publish.assert_called_once_with(wait=True)