Esempio n. 1
0
 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()
Esempio n. 2
0
 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()
Esempio n. 3
0
 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()
Esempio n. 4
0
 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')