def test_revert_raises_error_when_backup_not_found(self): side_effect = self.command_checker( args_parsers=args_parser, expected_args_set=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, ], side_effects=[ SucceededResult(), # manager status docker.ImageNotFoundError(), # image info ], ) with mock.patch.object(fabricio, 'run', side_effect=side_effect): fab.env.command = 'test_k8s_revert_raises_error_when_backup_not_found' configuration = kubernetes.Configuration(name='k8s') with self.assertRaises(docker.ServiceError): configuration.revert()
def test_revert_raises_error_when_backup_not_found(self): side_effect = self.command_checker( args_parsers=[args_parser, docker_inspect_args_parser], expected_args_set=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-backup-stack:stack', }, ], side_effects=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info ], ) with mock.patch.object(fabricio, 'run', side_effect=side_effect): stack = docker.Stack(name='stack') with self.assertRaises(docker.ServiceError): stack.revert()
def test_update(self, put, *args): cases = dict( worker=dict( init_kwargs=dict(name='stack'), update_kwargs={}, side_effect=[ SucceededResult(' Is Manager: false'), # manager status ], args_parser=[ args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, ], expected_result=False, all_hosts=['host1', 'host2'], ), no_changes=dict( init_kwargs=dict(name='stack'), update_kwargs={}, side_effect=[ SucceededResult(' Is Manager: true'), # manager status SucceededResult( json.dumps([{ 'Config': { 'Labels': { 'fabricio.stack.compose.stack': 'Y29tcG9zZS55bWw=', 'fabricio.stack.images.stack': 'e30=', }, } }])), # image info ], args_parser=[ args_parser, docker_inspect_args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, ], expected_result=False, expected_compose_file='docker-compose.yml', ), forced=dict( init_kwargs=dict(name='stack'), update_kwargs=dict(force=True), side_effect=[ SucceededResult(' Is Manager: true'), # manager status SucceededResult(), # stack deploy RuntimeError(), # update sentinel images SucceededResult(), # stack images SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='docker-compose.yml', should_upload_compose_file=True, ), created=dict( init_kwargs=dict(name='stack'), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult(), # stack images SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='docker-compose.yml', should_upload_compose_file=True, ), created_skip_sentinels_errors=dict( init_kwargs=dict(name='stack'), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # stack deploy RuntimeError(), # update sentinel images RuntimeError(), # stack images RuntimeError(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='docker-compose.yml', should_upload_compose_file=True, ), created_with_custom_compose=dict( init_kwargs=dict(name='stack', options=dict(compose_file='compose.yml')), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult(), # stack images SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='compose.yml', should_upload_compose_file=True, ), created_with_custom_compose2=dict( init_kwargs=dict(name='stack', options={'compose-file': 'compose.yml'}), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult(), # stack images SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='compose.yml', should_upload_compose_file=True, ), created_with_custom_image=dict( init_kwargs=dict(name='stack', image='image:tag'), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult(), # stack images SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM image:tag\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file_name='docker-compose.yml', should_upload_compose_file=True, ), created_with_custom_image_update_params=dict( init_kwargs=dict(name='stack', image='image:tag'), update_kwargs=dict(tag='new-tag', registry='registry', account='account'), side_effect=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult(), # stack images SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM registry/account/image:new-tag\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file_name='docker-compose.yml', should_upload_compose_file=True, ), created_from_empty_image_with_custom_image_update_params=dict( init_kwargs=dict(name='stack'), update_kwargs=dict(tag='registry/account/image:tag'), side_effect=[ SucceededResult(' Is Manager: true'), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult(), # stack images SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': [ 'echo', 'FROM registry/account/image:tag\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file_name='docker-compose.yml', should_upload_compose_file=True, ), updated_compose_changed=dict( init_kwargs=dict(name='stack'), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status SucceededResult( json.dumps([{ 'Config': { 'Labels': { 'fabricio.stack.compose.stack': 'b2xkLWNvbXBvc2UueW1s', 'fabricio.stack.images.stack': 'eyJpbWFnZTp0YWciOiAiZGlnZXN0In0=', }, } }])), # image info SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult('service image:tag'), # stack images SucceededResult(), # image pull SucceededResult('digest'), # images digests SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': ['docker', 'pull', 'image:tag'], }, { 'args': [ 'docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image:tag' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=eyJpbWFnZTp0YWciOiAiZGlnZXN0In0=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='docker-compose.yml', should_upload_compose_file=True, ), updated_image_changed=dict( init_kwargs=dict(name='stack'), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status SucceededResult( json.dumps([{ 'Config': { 'Labels': { 'fabricio.stack.compose.stack': 'Y29tcG9zZS55bWw=', 'fabricio.stack.images.stack': 'eyJpbWFnZTp0YWciOiAiZGlnZXN0In0=', }, } }])), # image info SucceededResult(), # image pull SucceededResult('new-digest'), # images digests SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult('service image:tag'), # stack images SucceededResult(), # image pull SucceededResult('new-digest'), # images digests SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': ['docker', 'pull', 'image:tag'], }, { 'args': [ 'docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image:tag' ], }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': ['docker', 'pull', 'image:tag'], }, { 'args': [ 'docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image:tag' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=eyJpbWFnZTp0YWciOiAibmV3LWRpZ2VzdCJ9\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='docker-compose.yml', should_upload_compose_file=True, ), updated_images_changed=dict( init_kwargs=dict(name='stack'), update_kwargs=dict(), side_effect=[ SucceededResult(' Is Manager: true'), # manager status SucceededResult( json.dumps([{ 'Config': { 'Labels': { 'fabricio.stack.compose.stack': 'Y29tcG9zZS55bWw=', 'fabricio.stack.images.stack': 'eyJpbWFnZTE6dGFnIjogImRpZ2VzdDEiLCAiaW1hZ2UyOnRhZyI6ICJkaWdlc3QyIn0=', }, } }])), # image info SucceededResult(), # image1 pull SucceededResult(), # image2 pull SucceededResult( 'new-digest1\nnew-digest2\n'), # images digests SucceededResult(), # stack deploy SucceededResult(), # update sentinel images SucceededResult( 'service1 image1:tag\nservice2 image2:tag\n' ), # stack images SucceededResult(), # image1 pull SucceededResult(), # image2 pull SucceededResult( 'new-digest1\nnew-digest2\n'), # images digests SucceededResult(), # build new sentinel image ], args_parser=[ args_parser, docker_inspect_args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, args_parser, ], expected_command_args=[ { 'args': ['docker', 'info', '2>&1', '|', 'grep', 'Is Manager:'], }, { 'executable': ['docker', 'inspect'], 'type': 'image', 'image_or_container': 'fabricio-current-stack:stack', }, { 'args': ['docker', 'pull', 'image1:tag'], }, { 'args': ['docker', 'pull', 'image2:tag'], }, { 'args': [ 'docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image1:tag', 'image2:tag' ], }, { 'args': [ 'docker', 'stack', 'deploy', '--compose-file=docker-compose.yml', 'stack' ], }, { 'args': [ 'docker', 'rmi', 'fabricio-backup-stack:stack;', 'docker', 'tag', 'fabricio-current-stack:stack', 'fabricio-backup-stack:stack;', 'docker', 'rmi', 'fabricio-current-stack:stack' ], }, { 'args': [ 'docker', 'stack', 'services', '--format', '{{.Name}} {{.Image}}', 'stack' ], }, { 'args': ['docker', 'pull', 'image1:tag'], }, { 'args': ['docker', 'pull', 'image2:tag'], }, { 'args': [ 'docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image1:tag', 'image2:tag' ], }, { 'args': [ 'echo', 'FROM scratch\nLABEL fabricio.stack.compose.stack=Y29tcG9zZS55bWw= fabricio.stack.images.stack=eyJpbWFnZTE6dGFnIjogIm5ldy1kaWdlc3QxIiwgImltYWdlMjp0YWciOiAibmV3LWRpZ2VzdDIifQ==\n', '|', 'docker', 'build', '--tag', 'fabricio-current-stack:stack', '-' ], }, ], expected_result=True, expected_compose_file='docker-compose.yml', should_upload_compose_file=True, ), ) for case, data in cases.items(): with self.subTest(case): fab.env.command = '{0}__{1}'.format(self, case) with mock.patch.dict( fab.env, dict(all_hosts=data.get('all_hosts', ['host']))): service.open.return_value = six.BytesIO(b'compose.yml') service.open.reset_mock() put.reset_mock() stack = docker.Stack(**data.get('init_kwargs', {})) side_effect = self.command_checker( args_parsers=data.get('args_parser', []), expected_args_set=data.get('expected_command_args', []), side_effects=data.get('side_effect', []), ) with mock.patch.object(fabricio, 'run', side_effect=side_effect): with mock.patch('six.BytesIO') as compose_file: result = stack.update( **data.get('update_kwargs', {})) self.assertEqual(data['expected_result'], result) expected_compose_file_name = data.get( 'expected_compose_file_name') if expected_compose_file_name: service.open.assert_called_once_with( expected_compose_file_name, 'rb') if data.get('should_upload_compose_file', False): put.assert_called_once() compose_file.assert_called_once_with(b'compose.yml') else: put.assert_not_called()
def test_update(self, put, *args): cases = dict( worker=dict( init_kwargs=dict(), update_kwargs={}, side_effect=[ FailedResult(), # manager status ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, ], expected_result=None, all_hosts=['host1', 'host2'], ), no_changes=dict( init_kwargs=dict(), update_kwargs={}, side_effect=[ SucceededResult(), # manager status SucceededResult(json.dumps([{'Config': { 'Labels': { 'fabricio.configuration': 'azhzLnltbA==', # k8s.yml 'fabricio.digests': 'e30=', # {} }, }}])), # image info ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, ], expected_result=False, expected_config_filename='k8s.yml', ), forced=dict( init_kwargs=dict(), update_kwargs=dict(force=True), side_effect=[ SucceededResult(), # manager status SucceededResult(), # configuration deploy docker.ImageNotFoundError(), # backup image info fabricio.Error(), # update sentinel images SucceededResult(), # configuration images SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['echo', 'FROM scratch\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), created=dict( init_kwargs=dict(), update_kwargs=dict(), side_effect=[ SucceededResult(), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # configuration deploy docker.ImageNotFoundError(), # image info SucceededResult(), # update sentinel images SucceededResult(), # configuration images SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['echo', 'FROM scratch\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), created_skip_sentinels_errors=dict( init_kwargs=dict(), update_kwargs=dict(), side_effect=[ SucceededResult(), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # configuration deploy docker.ImageNotFoundError(), # image info fabricio.Error(), # update sentinel images fabricio.Error(), # configuration images fabricio.Error(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['echo', 'FROM scratch\nLABEL fabricio.configuration=azhzLnltbA==\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), created_with_custom_image=dict( init_kwargs=dict(image='image:tag'), update_kwargs=dict(), side_effect=[ SucceededResult(), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # configuration deploy docker.ImageNotFoundError(), # image info SucceededResult(), # update sentinel images SucceededResult(), # configuration images SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['echo', 'FROM image:tag\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), created_with_custom_image_update_params=dict( init_kwargs=dict(image='image:tag'), update_kwargs=dict(tag='new-tag', registry='registry', account='account'), side_effect=[ SucceededResult(), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # configuration deploy docker.ImageNotFoundError(), # image info SucceededResult(), # update sentinel images SucceededResult(), # configuration images SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['echo', 'FROM registry/account/image:new-tag\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), created_from_empty_image_with_custom_image_update_params=dict( init_kwargs=dict(), update_kwargs=dict(tag='registry/account/image:tag'), side_effect=[ SucceededResult(), # manager status docker.ImageNotFoundError(), # image info SucceededResult(), # configuration deploy docker.ImageNotFoundError(), # image info SucceededResult(), # update sentinel images SucceededResult(), # configuration images SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['echo', 'FROM registry/account/image:tag\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=e30=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), updated_configuration_changed=dict( init_kwargs=dict(), update_kwargs=dict(), side_effect=[ SucceededResult(), # manager status SucceededResult(json.dumps([{'Config': { 'Labels': { 'fabricio.configuration': 'b2xkLWNvbXBvc2UueW1s', 'fabricio.digests': 'eyJpbWFnZTp0YWciOiAiZGlnZXN0In0=', }, }}])), # image info SucceededResult(), # configuration deploy SucceededResult('[{"Parent": "backup_parent_id"}]'), # backup image info SucceededResult(), # update sentinel images SucceededResult('kind name image:tag'), # configuration images SucceededResult(), SucceededResult(), SucceededResult(), # image pull SucceededResult('digest'), # images digests SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s', 'backup_parent_id;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['docker', 'tag', 'image:tag', 'fabricio-temp-image:image', '&&', 'docker', 'rmi', 'image:tag']}, {'args': ['docker', 'pull', 'image:tag']}, {'args': ['docker', 'rmi', 'fabricio-temp-image:image']}, {'args': ['docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image:tag']}, {'args': ['echo', 'FROM scratch\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=eyJpbWFnZTp0YWciOiAiZGlnZXN0In0=\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), updated_image_changed=dict( init_kwargs=dict(), update_kwargs=dict(), side_effect=[ SucceededResult(), # manager status SucceededResult(json.dumps([{'Config': { 'Labels': { 'fabricio.configuration': 'azhzLnltbA==', 'fabricio.digests': 'eyJpbWFnZTp0YWciOiAiZGlnZXN0In0=', }, }}])), # image info SucceededResult(), SucceededResult(), SucceededResult(), # image pull SucceededResult('new-digest'), # images digests SucceededResult(), # configuration deploy SucceededResult('[{"Parent": "backup_parent_id"}]'), # backup image info SucceededResult(), # update sentinel images SucceededResult('kind name image:tag'), # configuration images SucceededResult(), SucceededResult(), SucceededResult(), # image pull SucceededResult('new-digest'), # images digests SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['docker', 'tag', 'image:tag', 'fabricio-temp-image:image', '&&', 'docker', 'rmi', 'image:tag']}, {'args': ['docker', 'pull', 'image:tag']}, {'args': ['docker', 'rmi', 'fabricio-temp-image:image']}, {'args': ['docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image:tag']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s', 'backup_parent_id;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['docker', 'tag', 'image:tag', 'fabricio-temp-image:image', '&&', 'docker', 'rmi', 'image:tag']}, {'args': ['docker', 'pull', 'image:tag']}, {'args': ['docker', 'rmi', 'fabricio-temp-image:image']}, {'args': ['docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image:tag']}, {'args': ['echo', 'FROM scratch\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=eyJpbWFnZTp0YWciOiAibmV3LWRpZ2VzdCJ9\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), updated_images_changed=dict( init_kwargs=dict(), update_kwargs=dict(), side_effect=[ SucceededResult(), # manager status SucceededResult(json.dumps([{'Config': { 'Labels': { 'fabricio.configuration': 'azhzLnltbA==', 'fabricio.digests': 'eyJpbWFnZTE6dGFnIjogImRpZ2VzdDEiLCAiaW1hZ2UyOnRhZyI6ICJkaWdlc3QyIn0=', }, }}])), # image info SucceededResult(), SucceededResult(), SucceededResult(), # image1 pull SucceededResult(), SucceededResult(), SucceededResult(), # image2 pull SucceededResult('new-digest1\nnew-digest2\n'), # images digests SucceededResult(), # configuration deploy SucceededResult('[{"Parent": "backup_parent_id"}]'), # backup image info SucceededResult(), # update sentinel images SucceededResult('kind1 image1 image1:tag\nkind2 image2 image2:tag\n'), # configuration images SucceededResult(), SucceededResult(), SucceededResult(), # image1 pull SucceededResult(), SucceededResult(), SucceededResult(), # image2 pull SucceededResult('new-digest1\nnew-digest2\n'), # images digests SucceededResult(), # build new sentinel image ], expected_command_args=[ {'args': ['kubectl', 'config', 'current-context']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']}, {'args': ['docker', 'tag', 'image1:tag', 'fabricio-temp-image:image1', '&&', 'docker', 'rmi', 'image1:tag']}, {'args': ['docker', 'pull', 'image1:tag']}, {'args': ['docker', 'rmi', 'fabricio-temp-image:image1']}, {'args': ['docker', 'tag', 'image2:tag', 'fabricio-temp-image:image2', '&&', 'docker', 'rmi', 'image2:tag']}, {'args': ['docker', 'pull', 'image2:tag']}, {'args': ['docker', 'rmi', 'fabricio-temp-image:image2']}, {'args': ['docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image1:tag', 'image2:tag']}, {'args': ['kubectl', 'apply', '--filename=k8s.yml']}, {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']}, {'args': ['docker', 'rmi', 'fabricio-backup-kubernetes:k8s', 'backup_parent_id;', 'docker', 'tag', 'fabricio-current-kubernetes:k8s', 'fabricio-backup-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-current-kubernetes:k8s']}, {'args': ['kubectl', 'get', '--output', 'go-template', '--filename', 'k8s.yml', '--template', r'{{define "images"}}{{$kind := .kind}}{{$name := .metadata.name}}{{with .spec.template.spec.containers}}{{range .}}{{$kind}}/{{$name}} {{.name}} {{.image}}{{"\n"}}{{end}}{{end}}{{end}}{{if eq .kind "List"}}{{range .items}}{{template "images" .}}{{end}}{{else}}{{template "images" .}}{{end}}']}, {'args': ['docker', 'tag', 'image1:tag', 'fabricio-temp-image:image1', '&&', 'docker', 'rmi', 'image1:tag']}, {'args': ['docker', 'pull', 'image1:tag']}, {'args': ['docker', 'rmi', 'fabricio-temp-image:image1']}, {'args': ['docker', 'tag', 'image2:tag', 'fabricio-temp-image:image2', '&&', 'docker', 'rmi', 'image2:tag']}, {'args': ['docker', 'pull', 'image2:tag']}, {'args': ['docker', 'rmi', 'fabricio-temp-image:image2']}, {'args': ['docker', 'inspect', '--type', 'image', '--format', '{{index .RepoDigests 0}}', 'image1:tag', 'image2:tag']}, {'args': ['echo', 'FROM scratch\nLABEL fabricio.configuration=azhzLnltbA== fabricio.digests=eyJpbWFnZTE6dGFnIjogIm5ldy1kaWdlc3QxIiwgImltYWdlMjp0YWciOiAibmV3LWRpZ2VzdDIifQ==\n', '|', 'docker', 'build', '--tag', 'fabricio-current-kubernetes:k8s', '-']}, ], expected_result=True, expected_config_filename='k8s.yml', ), ) for case, data in cases.items(): with self.subTest(case): fab.env.command = '{0}__{1}'.format(self, case) with mock.patch.dict(fab.env, dict(all_hosts=data.get('all_hosts', ['host']))): stack_module.open.return_value = six.BytesIO(b'k8s.yml') stack_module.open.reset_mock() put.reset_mock() configuration = kubernetes.Configuration( name='k8s', options={'filename': 'k8s.yml'}, **data.get('init_kwargs', {}) ) side_effect = self.command_checker( args_parsers=args_parser, expected_args_set=data.get('expected_command_args', []), side_effects=data.get('side_effect', []), ) with mock.patch.object(fabricio, 'run', side_effect=side_effect): with mock.patch('six.BytesIO') as filename: result = configuration.update(**data.get('update_kwargs', {})) self.assertEqual(data['expected_result'], result) expected_compose_file_name = data.get('expected_config_filename') if expected_compose_file_name: stack_module.open.assert_called_once_with(expected_compose_file_name, 'rb') put.assert_called_once() filename.assert_called_once_with(b'k8s.yml')