def test_resume_with_unknown_upload_id(vcr_fixture, runner, config_file, config_profile, content_input_file, test_id): object_name = 'a' upload_id = 'UNKNOWN_UPLOAD_ID' # resume multipart upload result = invoke(runner, config_file, config_profile, [ 'object', 'resume-put', '-ns', util.NAMESPACE, '-bn', "cli_temp_multipart_bucket_" + test_id, '--name', object_name, '--file', content_input_file, '--upload-id', upload_id ]) util.validate_service_error(result, error_message='No such upload')
def test_put_object_multipart_and_parallel_options(runner, config_file, config_profile, content_input_file): object_name = 'a' # validate error is returned if --parallel-upload-count and --disable-parallel-uploads are used result = invoke(runner, config_file, config_profile, [ 'object', 'put', '-ns', util.NAMESPACE, '-bn', 'unknown_bucket', '--name', object_name, '--file', content_input_file, '--parallel-upload-count', '2', '--disable-parallel-uploads' ]) util.validate_service_error(result) # validate error is returned if --parallel-upload-count and --no-multipart are used result = invoke(runner, config_file, config_profile, [ 'object', 'put', '-ns', util.NAMESPACE, '-bn', 'unknown_bucket', '--name', object_name, '--file', content_input_file, '--parallel-upload-count', '2', '--no-multipart' ]) util.validate_service_error(result)
def test_boot_volume_clone_backup(network_resources): with test_config_container.create_vcr(cassette_library_dir=CASSETTE_LIBRARY_DIR).use_cassette('boot_volume_test_boot_volume_clone_backup.yml'): boot_volume_id = None instance_ocid = None backup_boot_volume_id = None cloned_boot_volume_id = None backup_id = None try: instance_name = util.random_name('boot_vol_instance') image_id = util.oracle_linux_image() shape = 'VM.Standard1.1' hostname_label = util.random_name('bootvolinst', insert_underscore=False) boot_volume_size_in_gbs = '51' result = invoke([ 'compute', 'instance', 'launch', '--compartment-id', util.COMPARTMENT_ID, '--availability-domain', util.availability_domain(), '--display-name', instance_name, '--subnet-id', network_resources[1], '--image-id', image_id, '--shape', shape, '--hostname-label', hostname_label, '--boot-volume-size-in-gbs', boot_volume_size_in_gbs, '--wait-for-state', 'RUNNING', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS ]) util.validate_response(result, json_response_expected=False) instance_data = util.get_json_from_mixed_string(result.output)['data'] instance_ocid = instance_data['id'] assert 'image' == instance_data['source-details']['source-type'] assert image_id == instance_data['source-details']['image-id'] result = invoke([ 'compute', 'boot-volume-attachment', 'list', '-c', util.COMPARTMENT_ID, '--availability-domain', util.availability_domain(), '--instance-id', instance_data['id'] ]) util.validate_response(result) parsed_result = json.loads(result.output) assert len(parsed_result['data']) == 1 boot_volume_id = parsed_result['data'][0]['boot-volume-id'] result = invoke([ 'bv', 'boot-volume', 'get', '--boot-volume-id', boot_volume_id ]) util.validate_response(result) parsed_result = json.loads(result.output) boot_volume_size_in_gbs = parsed_result['data']['size-in-gbs'] assert boot_volume_size_in_gbs == int(boot_volume_size_in_gbs) result = invoke([ 'compute', 'instance', 'terminate', '--instance-id', instance_ocid, '--wait-for-state', 'TERMINATED', '--preserve-boot-volume', 'true', '--force' ]) util.validate_response(result, json_response_expected=False) instance_ocid = None # Since we preserved the volume it should still be available result = invoke(['bv', 'boot-volume', 'get', '--boot-volume-id', boot_volume_id]) util.validate_response(result) parsed_result = json.loads(result.output) assert util.availability_domain() == parsed_result['data']['availability-domain'] assert 'AVAILABLE' == parsed_result['data']['lifecycle-state'] assert image_id == parsed_result['data']['image-id'] size_in_gbs = int(parsed_result['data']['size-in-gbs']) new_size_in_gbs = size_in_gbs + 10 # Resize boot volume to new_size_in_gbs result = invoke(['bv', 'boot-volume', 'update', '--boot-volume-id', boot_volume_id, '--size-in-gbs', str(new_size_in_gbs), '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) util.validate_response(result, json_response_expected=False) # Since we preserved the volume it should still be available result = invoke(['bv', 'boot-volume', 'get', '--boot-volume-id', boot_volume_id]) util.validate_response(result) parsed_result = json.loads(result.output) assert 'AVAILABLE' == parsed_result['data']['lifecycle-state'] assert new_size_in_gbs == int(parsed_result['data']['size-in-gbs']) # Take a backup result = invoke(['bv', 'boot-volume-backup', 'create', '--boot-volume-id', boot_volume_id, '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) util.validate_response(result, json_response_expected=False) parsed_result = util.get_json_from_mixed_string(result.output) assert boot_volume_id == parsed_result['data']['boot-volume-id'] assert image_id == parsed_result['data']['image-id'] assert 'AVAILABLE' == parsed_result['data']['lifecycle-state'] backup_id = parsed_result['data']['id'] # Boot Volume Create Error cases # Error 1: No option specified result = invoke(['bv', 'boot-volume', 'create', '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) assert "An empty boot volume cannot be created. Please specify either --boot-volume-backup-id, --source-boot-volume-id or --source-volume-replica-id" in result.output # Error 2: Both options specified result = invoke(['bv', 'boot-volume', 'create', '--source-boot-volume-id', boot_volume_id[0], '--boot-volume-backup-id', boot_volume_id[0], '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) assert "You can only specify one of either --source-boot-volume-id, --boot-volume-backup-id or --source-volume-replica-id option" in result.output # Clone the boot volume (Error 1: Invalid Boot Volume ID) result = invoke(['bv', 'boot-volume', 'create', '--source-boot-volume-id', boot_volume_id[0], '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) util.validate_service_error(result, error_message="InvalidParameter") backup_policy_ids = get_backup_policy_ids() create_new_size_in_gbs = new_size_in_gbs + 10 # Clone the boot volume with bronze backup policy and larger size result = invoke(['bv', 'boot-volume', 'create', '--source-boot-volume-id', boot_volume_id, '--backup-policy-id', backup_policy_ids["bronze"], '--wait-for-state', 'AVAILABLE', '--size-in-gbs', str(create_new_size_in_gbs), '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) util.validate_response(result, json_response_expected=False) parsed_result = util.get_json_from_mixed_string(result.output) assert util.availability_domain() == parsed_result['data']['availability-domain'] assert 'AVAILABLE' == parsed_result['data']['lifecycle-state'] assert image_id == parsed_result['data']['image-id'] assert create_new_size_in_gbs == int(parsed_result['data']['size-in-gbs']) cloned_boot_volume_id = parsed_result['data']['id'] # Verify the backup policy result = invoke(['bv', 'volume-backup-policy-assignment', 'get-volume-backup-policy-asset-assignment', '--asset-id', cloned_boot_volume_id]) util.validate_response(result) parsed_result = json.loads(result.output) backup_policy_assignment_id = parsed_result["data"][0]["id"] assert parsed_result["data"][0]["policy-id"] == backup_policy_ids["bronze"] # Remove backup policy result = invoke(['bv', 'volume-backup-policy-assignment', 'delete', '--policy-assignment-id', backup_policy_assignment_id, '--force']) util.validate_response(result) # Change backup policy to silver result = invoke(['bv', 'volume-backup-policy-assignment', 'create', '--asset-id', cloned_boot_volume_id, '--policy-id', backup_policy_ids['silver']]) util.validate_response(result) parsed_result = json.loads(result.output) backup_policy_assignment_id = parsed_result["data"]["id"] assert parsed_result["data"]["policy-id"] == backup_policy_ids["silver"] # Remove the backup policy result = invoke(['bv', 'volume-backup-policy-assignment', 'delete', '--policy-assignment-id', backup_policy_assignment_id, '--force']) util.validate_response(result) # We can now launch an instance using that boot volume result = invoke([ 'compute', 'instance', 'launch', '--compartment-id', util.COMPARTMENT_ID, '--availability-domain', util.availability_domain(), '--display-name', instance_name, '--subnet-id', network_resources[1], '--shape', shape, '--hostname-label', hostname_label, '--source-boot-volume-id', cloned_boot_volume_id, '--wait-for-state', 'RUNNING', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS ]) util.validate_response(result, json_response_expected=False) instance_data = util.get_json_from_mixed_string(result.output)['data'] instance_ocid = instance_data['id'] assert 'bootVolume' == instance_data['source-details']['source-type'] assert cloned_boot_volume_id == instance_data['source-details']['boot-volume-id'] clean_up_instances(instance_ocid) cloned_boot_volume_id = None instance_ocid = None # Delete existing boot volume clean_up_boot_volume(boot_volume_id) boot_volume_id = None # Create boot volume from backup (Error 1: Invalid Backup Volume ID) result = invoke(['bv', 'boot-volume', 'create', '--boot-volume-backup-id', backup_id[0], '--availability-domain', util.availability_domain(), '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) util.validate_service_error(result, error_message="InvalidParameter") # Create boot volume from backup (Error 2: Availability domain not specified) result = invoke(['bv', 'boot-volume', 'create', '--boot-volume-backup-id', backup_id, '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) assert "An availability domain must be specified when restoring a boot volume from backup" in result.output # Create boot volume from backup result = invoke(['bv', 'boot-volume', 'create', '--boot-volume-backup-id', backup_id, '--availability-domain', util.availability_domain(), '--wait-for-state', 'AVAILABLE', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS]) util.validate_response(result, json_response_expected=False) parsed_result = util.get_json_from_mixed_string(result.output) assert util.availability_domain() == parsed_result['data']['availability-domain'] assert 'AVAILABLE' == parsed_result['data']['lifecycle-state'] assert image_id == parsed_result['data']['image-id'] backup_boot_volume_id = parsed_result['data']['id'] # We can now launch an instance using that boot volume result = invoke([ 'compute', 'instance', 'launch', '--compartment-id', util.COMPARTMENT_ID, '--availability-domain', util.availability_domain(), '--display-name', instance_name, '--subnet-id', network_resources[1], '--shape', shape, '--hostname-label', hostname_label, '--source-boot-volume-id', backup_boot_volume_id, '--wait-for-state', 'RUNNING', '--wait-interval-seconds', util.WAIT_INTERVAL_SECONDS ]) util.validate_response(result, json_response_expected=False) instance_data = util.get_json_from_mixed_string(result.output)['data'] instance_ocid = instance_data['id'] assert 'bootVolume' == instance_data['source-details']['source-type'] assert backup_boot_volume_id == instance_data['source-details']['boot-volume-id'] clean_up_instances(instance_ocid) backup_boot_volume_id = None instance_ocid = None finally: clean_up_instances(instance_ocid) clean_up_boot_volume(boot_volume_id) clean_up_boot_volume(cloned_boot_volume_id) clean_up_boot_volume(backup_boot_volume_id) clean_up_boot_volume_backup(backup_id)
def subtest_instance_console_connections(self): result = self.invoke([ 'compute', 'instance-console-connection', 'create', '--instance-id', self.instance_ocid, '--ssh-public-key-file', util.SSH_AUTHORIZED_KEYS_FILE ]) util.validate_response(result) instance_console_connection_details = json.loads(result.output) self.assertIsNotNone( instance_console_connection_details['data']['connection-string']) self.assertIsNotNone(instance_console_connection_details['data']['id']) self.assertIsNotNone( instance_console_connection_details['data']['lifecycle-state']) self.assertEquals( self.instance_ocid, instance_console_connection_details['data']['instance-id']) self.assertIsNotNone( instance_console_connection_details['data']['fingerprint']) result = self.invoke([ 'compute', 'instance-console-connection', 'get', '--instance-console-connection-id', instance_console_connection_details['data']['id'] ]) parsed_result = json.loads(result.output) self.assertEquals(instance_console_connection_details['data']['id'], parsed_result['data']['id']) self.assertEquals( instance_console_connection_details['data']['instance-id'], parsed_result['data']['instance-id']) self.assertEquals( instance_console_connection_details['data']['fingerprint'], parsed_result['data']['fingerprint']) self.assertEquals( instance_console_connection_details['data']['compartment-id'], parsed_result['data']['compartment-id']) self.assertEquals( instance_console_connection_details['data']['connection-string'], parsed_result['data']['connection-string']) self.assertEquals( {}, instance_console_connection_details['data']['freeform-tags']) self.assertEquals( {}, instance_console_connection_details['data']['defined-tags']) self.assertIsNotNone(parsed_result['data']['lifecycle-state']) private_key_file = 'C:\\Users\\oci\console.ppk' # noqa: W605 params = [ 'compute', 'instance-console-connection', 'get-plink-connection-string', '--instance-console-connection-id', instance_console_connection_details['data']['id'], '--private-key-file', private_key_file ] result = self.invoke(params) util.validate_response(result, json_response_expected=False) m = re.search( oci_cli_compute.compute_cli_extended. INSTANCE_CONSOLE_CONNECTION_STRING_INTERMEDIATE_HOST_REGEX, instance_console_connection_details['data']['connection-string']) intermediate_host = m.group(0) connection_template = 'Start-Job {{echo N | plink -ssh -N -i "{3}" -P 443 -l {1} {2} -L 5905:{0}:5905}}; sleep 5 ; plink -L 5900:localhost:5900 localhost -P 5905 -N -i "{3}" -l {1}' expected_plink_connection_string = connection_template.format( instance_console_connection_details['data']['instance-id'], instance_console_connection_details['data']['id'], intermediate_host, private_key_file) assert expected_plink_connection_string == result.output.strip() # confirm that error from internal call to GetConsoleConnection returns service error and non-zero status code params = [ 'compute', 'instance-console-connection', 'get-plink-connection-string', '--instance-console-connection-id', 'fake-instance-console-connection-id', '--private-key-file', private_key_file ] result = self.invoke(params) util.validate_service_error(result, error_message='ServiceError') keep_paginating = True next_page = None all_connections = [] while keep_paginating: if next_page: result = self.invoke([ 'compute', 'instance-console-connection', 'list', '--compartment-id', util.COMPARTMENT_ID, '--page', next_page ]) else: result = self.invoke([ 'compute', 'instance-console-connection', 'list', '--compartment-id', util.COMPARTMENT_ID ]) if result.output: parsed_result = json.loads(result.output) all_connections.extend(parsed_result['data']) if 'opc-next-page' in parsed_result: next_page = parsed_result['opc-next-page'] keep_paginating = next_page is not None else: keep_paginating = False else: keep_paginating = False match_found = False for conn in all_connections: if conn['id'] == instance_console_connection_details['data']['id']: match_found = True self.assertEquals( instance_console_connection_details['data']['instance-id'], conn['instance-id']) self.assertEquals( instance_console_connection_details['data']['fingerprint'], conn['fingerprint']) self.assertEquals( instance_console_connection_details['data'] ['compartment-id'], conn['compartment-id']) self.assertEquals( instance_console_connection_details['data'] ['connection-string'], conn['connection-string']) self.assertIsNotNone(conn['lifecycle-state']) break self.assertTrue(match_found) self.invoke([ 'compute', 'instance-console-connection', 'delete', '--instance-console-connection-id', instance_console_connection_details['data']['id'], '--force' ]) result = self.invoke([ 'compute', 'instance-console-connection', 'get', '--instance-console-connection-id', instance_console_connection_details['data']['id'] ]) parsed_result = json.loads(result.output) if 'DELET' not in parsed_result['data']['lifecycle-state']: print("parsed_result=" + str(parsed_result) + ", lifecycle-state=" + str(parsed_result['data']['lifecycle-state'])) util.vcr_mode_aware_sleep(60) result = self.invoke([ 'compute', 'instance-console-connection', 'get', '--instance-console-connection-id', instance_console_connection_details['data']['id'] ]) parsed_result = json.loads(result.output) self.assertTrue( parsed_result['data']['lifecycle-state'] == 'DELETED' or parsed_result['data']['lifecycle-state'] == 'DELETING')
def test_run_all_operations(runner, config_file, config_profile, debug): """Successfully calls every operation with required arguments only.""" bucket_name = 'cli_temp_bucket_' + str(random.randint(0, 1000000)) + ('_debug' if debug else '_no_debug') object_name = 'a' # ns get result = invoke(runner, config_file, config_profile, ['ns', 'get'], debug=debug) validate_response(result, includes_debug_data=debug) assert util.NAMESPACE in result.output # bucket create result = invoke(runner, config_file, config_profile, ['bucket', 'create', '-ns', util.NAMESPACE, '--compartment-id', util.COMPARTMENT_ID, '--name', bucket_name], debug=debug) validate_response(result, includes_debug_data=debug) # object put result = invoke(runner, config_file, config_profile, ['object', 'put', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_INPUT_FILE, '--encryption-key-file', GENERATED_ENC_KEY1_FILE], debug=debug) validate_response(result, includes_debug_data=debug) # object get without SSE-C headers should result in a 400 result = invoke(runner, config_file, config_profile, ['object', 'get', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_OUTPUT_FILE], debug=debug) util.validate_service_error(result, 'The service returned error code 400', debug) # object get with the wrong SSE-C key should result in a 403 result = invoke(runner, config_file, config_profile, ['object', 'get', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_OUTPUT_FILE, '--encryption-key-file', GENERATED_ENC_KEY2_FILE], debug=debug) util.validate_service_error(result, 'The service returned error code 403', debug) # object get with the correct SSE-C key result = invoke(runner, config_file, config_profile, ['object', 'get', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_OUTPUT_FILE, '--encryption-key-file', GENERATED_ENC_KEY1_FILE], debug=debug) validate_response(result, json_response_expected=False, includes_debug_data=debug) assertEqual(get_file_content(CONTENT_INPUT_FILE), get_file_content(CONTENT_OUTPUT_FILE)) # object head without any SSE-C data should fail with 400 result = invoke(runner, config_file, config_profile, ['object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name], debug=debug) util.validate_service_error(result, 'The service returned error code 400', debug) # object head with an incorrect SSE-C key should fail with 403 result = invoke(runner, config_file, config_profile, ['object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY2_FILE], debug=debug) util.validate_service_error(result, 'The service returned error code 403', debug) # object head with the right SSE-C key result = invoke(runner, config_file, config_profile, ['object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY1_FILE], debug=debug) validate_response(result, includes_debug_data=debug) # object list (doesn't require SSE-C information) result = invoke(runner, config_file, config_profile, ['object', 'list', '-ns', util.NAMESPACE, '-bn', bucket_name], debug=debug) validate_response(result, includes_debug_data=debug) # object delete (doesn't require SSE-C information) result = invoke(runner, config_file, config_profile, ['object', 'delete', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name], input='n', debug=debug) assert result.exit_code != 0 result = invoke(runner, config_file, config_profile, ['object', 'delete', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name], input='y', debug=debug) validate_response(result, json_response_expected=False, includes_debug_data=debug) # bucket delete result = invoke(runner, config_file, config_profile, ['bucket', 'delete', '-ns', util.NAMESPACE, '--name', bucket_name, '--force'], debug=debug) validate_response(result, includes_debug_data=debug)
def test_run_all_operations(runner, config_file, config_profile, debug): """Successfully calls every operation with required arguments only.""" bucket_name = 'cli_temp_bucket_' + str(random.randint( 0, 1000000)) + ('_debug' if debug else '_no_debug') object_name = 'a' # ns get result = invoke(runner, config_file, config_profile, ['ns', 'get'], debug=debug) validate_response(result, includes_debug_data=debug) assert util.NAMESPACE in result.output # bucket create result = invoke( runner, config_file, config_profile, [ 'bucket', 'create', '-ns', util.NAMESPACE, '--compartment-id', util.COMPARTMENT_ID, '--name', bucket_name ], debug=debug) validate_response(result, includes_debug_data=debug) # object put result = invoke( runner, config_file, config_profile, [ 'object', 'put', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_INPUT_FILE, '--encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) validate_response(result, includes_debug_data=debug) # object get without SSE-C headers should result in a 400 result = invoke( runner, config_file, config_profile, [ 'object', 'get', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_OUTPUT_FILE ], debug=debug) util.validate_service_error(result, 'The service returned error code 400', debug) # object get with the wrong SSE-C key should result in a 403 result = invoke( runner, config_file, config_profile, [ 'object', 'get', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_OUTPUT_FILE, '--encryption-key-file', GENERATED_ENC_KEY2_FILE ], debug=debug) util.validate_service_error(result, 'The service returned error code 403', debug) # object get with the correct SSE-C key result = invoke( runner, config_file, config_profile, [ 'object', 'get', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--file', CONTENT_OUTPUT_FILE, '--encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) validate_response(result, json_response_expected=False, includes_debug_data=debug) assertEqual(get_file_content(CONTENT_INPUT_FILE), get_file_content(CONTENT_OUTPUT_FILE)) # object head without any SSE-C data should fail with 400 result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name ], debug=debug) util.validate_service_error(result, 'The service returned error code 400', debug) # object head with an incorrect SSE-C key should fail with 403 result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY2_FILE ], debug=debug) util.validate_service_error(result, 'The service returned error code 403', debug) # object head with the right SSE-C key result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) validate_response(result, includes_debug_data=debug) # object reencrypt using the default/Oracle-managed key result = invoke(runner, config_file, config_profile, [ 'object', 'reencrypt', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--source-encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) validate_response(result, includes_debug_data=debug) # reencrypting the object again using the default/Oracle-managed key should not fail (no-op) result = invoke(runner, config_file, config_profile, [ 'object', 'reencrypt', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name ], debug=debug) validate_response(result, includes_debug_data=debug) # object head without any SSE-C data should succeed result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name ], debug=debug) validate_response(result, includes_debug_data=debug) # reencrypt the object using an SSE-C key result = invoke(runner, config_file, config_profile, [ 'object', 'reencrypt', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) validate_response(result, includes_debug_data=debug) # object head without any SSE-C data should fail result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name ], debug=debug) util.validate_service_error(result, 'The service returned error code 400', debug) # object head with the right SSE-C key should succeed result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) validate_response(result, includes_debug_data=debug) # reencrypt the object using yet another SSE-C key result = invoke( runner, config_file, config_profile, [ 'object', 'reencrypt', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--source-encryption-key-file', GENERATED_ENC_KEY1_FILE, '--encryption-key-file', GENERATED_ENC_KEY2_FILE ], debug=debug) validate_response(result, includes_debug_data=debug) # object head without any SSE-C data should fail result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name ], debug=debug) util.validate_service_error(result, 'The service returned error code 400', debug) # object head with an incorrect SSE-C key should fail with 403 result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) util.validate_service_error(result, 'The service returned error code 403', debug) # object head with the right SSE-C key should succeed result = invoke(runner, config_file, config_profile, [ 'object', 'head', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--encryption-key-file', GENERATED_ENC_KEY2_FILE ], debug=debug) validate_response(result, includes_debug_data=debug) # specifying both KMS and SSE-C encryption keys to reencrypt the object should result in a 400 error result = invoke( runner, config_file, config_profile, [ 'object', 'reencrypt', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name, '--kms-key-id', 'kms123456', '--encryption-key-file', GENERATED_ENC_KEY1_FILE ], debug=debug) util.validate_service_error( result, 'The object re-encryption key must be specified either in the kmsKeyId field or in the sseCustomerKey field, but not in both', debug) # object list (doesn't require SSE-C information) result = invoke( runner, config_file, config_profile, ['object', 'list', '-ns', util.NAMESPACE, '-bn', bucket_name], debug=debug) validate_response(result, includes_debug_data=debug) # object delete (doesn't require SSE-C information) result = invoke(runner, config_file, config_profile, [ 'object', 'delete', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name ], input='n', debug=debug) assert result.exit_code != 0 result = invoke(runner, config_file, config_profile, [ 'object', 'delete', '-ns', util.NAMESPACE, '-bn', bucket_name, '--name', object_name ], input='y', debug=debug) validate_response(result, json_response_expected=False, includes_debug_data=debug) # bucket delete result = invoke(runner, config_file, config_profile, [ 'bucket', 'delete', '-ns', util.NAMESPACE, '--name', bucket_name, '--force' ], debug=debug) validate_response(result, includes_debug_data=debug)
def test_patch_rrset_records(zone, runner, config_file, config_profile): zone_id = zone[0] zone_name = zone[1] failing_record_operations = [{ "operation": "REQUIRE", "domain": zone_name, "isProtected": True, "rdata": "127.0.0.1", "recordHash": "abc123", "rrsetVersion": "1", "rtype": "A", "ttl": 86400 }] params = [ 'record', 'rrset', 'patch', '--zone-name-or-id', zone_name, '--domain', zone_name, '--rtype', 'A', '--items', json.dumps(failing_record_operations) ] result = invoke(runner, config_file, config_profile, params) util.validate_service_error(result) successful_record_operations = [{ "operation": "ADD", "domain": zone_name, "isProtected": True, "rdata": "127.0.0.1", "recordHash": "abc123", "rrsetVersion": "1", "rtype": "A", "ttl": 86400 }] params = [ 'record', 'rrset', 'patch', '--zone-name-or-id', zone_id, '--domain', zone_name, '--rtype', 'A', '--items', json.dumps(successful_record_operations) ] result = invoke(runner, config_file, config_profile, params) util.validate_response(result) params = [ 'record', 'rrset', 'get', '--zone-name-or-id', zone_id, '--domain', zone_name, '--rtype', 'A' ] result = invoke(runner, config_file, config_profile, params) util.validate_response(result) records = json.loads(result.output)['data']['items'] a_record = [record for record in records if record['rtype'] == 'A'][0] # remove added TXT record remove_record_operation = [{ "operation": "REMOVE", "domain": zone_name, "rdata": a_record['rdata'], "recordHash": a_record['record-hash'], "rtype": a_record['rtype'] }] params = [ 'record', 'rrset', 'patch', '--zone-name-or-id', zone_id, '--domain', zone_name, '--rtype', 'A', '--items', json.dumps(remove_record_operation) ] result = invoke(runner, config_file, config_profile, params) util.validate_response(result) # retrieve zone to determine current version params = ['zone', 'get', '--zone-name-or-id', zone_id] result = invoke(runner, config_file, config_profile, params) util.validate_response(result) current_zone_version = json.loads(result.output)['data']['version'] # fetch zone records list for current version params = [ 'record', 'rrset', 'get', '--zone-name-or-id', zone_id, '--domain', zone_name, '--rtype', 'A', '--zone-version', current_zone_version ] result = invoke(runner, config_file, config_profile, params) util.validate_response(result) # assert that TXT record was removed remaining_a_records = [ record for record in json.loads(result.output)['data']['items'] if record['rtype'] == 'A' ] assert len(remaining_a_records) == 0