def test_revert_does_not_rollback_sentinels_on_error(self, *args):
     with mock.patch.object(kubernetes.Configuration, 'rotate_sentinel_images') as rotate_sentinel_images:
         fab.env.command = 'test_k8s_revert_does_not_rollback_sentinels_on_error'
         configuration = kubernetes.Configuration(name='k8s')
         with self.assertRaises(Exception):
             configuration.revert()
         configuration.revert()
         rotate_sentinel_images.assert_not_called()
 def test_destroy(self, run, upload, *_):
     config = kubernetes.Configuration(name='name', options=dict(filename='config.yml'))
     config.destroy()
     self.assertListEqual(
         [
             mock.call('docker inspect --type image fabricio-current-kubernetes:name', abort_exception=docker.ImageNotFoundError),
             mock.call('kubectl delete --filename=config.yml'),
             mock.call('docker inspect --type image fabricio-current-kubernetes:name', abort_exception=docker.ImageNotFoundError),
             mock.call('docker inspect --type image fabricio-backup-kubernetes:name', abort_exception=docker.ImageNotFoundError),
             mock.call('docker rmi fabricio-current-kubernetes:name fabricio-backup-kubernetes:name parent_id parent_id', ignore_errors=True),
         ],
         run.mock_calls,
     )
     upload.assert_called_once_with(b'k8s.yml')
 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()
Example #4
0
 def test_destroy(self, run, put, *_):
     run.side_effect = [SucceededResult('kind/name image-name image')] + [SucceededResult('[{"Parent": "parent_id"}]')] * 4
     with mock.patch('fabricio.operations.run', run):
         config = kubernetes.Configuration(name='name', options=dict(filename='config.yml'))
         config.destroy()
         self.assertListEqual(
             [
                 mock.call('kubectl get --output=go-template --filename=config.yml --template=\'{{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}}\''),
                 mock.call('kubectl delete --filename=config.yml'),
                 mock.call('docker inspect --type image fabricio-current-kubernetes:name', abort_exception=docker.ImageNotFoundError),
                 mock.call('docker inspect --type image fabricio-backup-kubernetes:name', abort_exception=docker.ImageNotFoundError),
                 mock.call('docker rmi fabricio-current-kubernetes:name fabricio-backup-kubernetes:name parent_id parent_id image', ignore_errors=True),
                 mock.call('rm -f config.yml', ignore_errors=True, sudo=False),
             ],
             run.mock_calls,
         )
         put.assert_called_once_with(b'configuration', 'config.yml')
 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')
 def test_revert(self, put, *args):
     cases = dict(
         worker=dict(
             init_kwargs=dict(),
             side_effect=[
                 FailedResult(),  # manager status
             ],
             expected_command_args=[
                 {'args': ['kubectl', 'config', 'current-context']},
             ],
             all_hosts=['host1', 'host2'],
         ),
         reverted=dict(
             init_kwargs=dict(),
             side_effect=[
                 SucceededResult(),  # manager status
                 SucceededResult(json.dumps([{'Config': {
                     'Labels': {
                         'fabricio.configuration': 'b2xkLWNvbXBvc2UueW1s',
                     },
                 }}])),  # image info
                 SucceededResult(),  # configuration deploy
                 SucceededResult('[{"Parent": "current_parent_id"}]'),  # current image info
                 SucceededResult(),  # update sentinel images
             ],
             expected_command_args=[
                 {'args': ['kubectl', 'config', 'current-context']},
                 {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']},
                 {'args': ['kubectl', 'apply', '--filename=k8s.yml']},
                 {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']},
                 {'args': ['docker', 'rmi', 'fabricio-current-kubernetes:k8s', 'current_parent_id;', 'docker', 'tag', 'fabricio-backup-kubernetes:k8s', 'fabricio-current-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-backup-kubernetes:k8s']},
             ],
             expected_compose_file=b'old-compose.yml',
         ),
         reverted_with_pod_update=dict(
             init_kwargs=dict(),
             side_effect=[
                 SucceededResult(),  # manager status
                 SucceededResult(json.dumps([{'Config': {
                     'Labels': {
                         'fabricio.configuration': 'Y29tcG9zZS55bWw=',  # compose.yml
                         'fabricio.digests': 'eyJpbWFnZTp0YWciOiAiZGlnZXN0In0=',  # {"image:tag": "digest"}
                     },
                 }}])),  # image info
                 SucceededResult(),  # configuration deploy
                 SucceededResult('kind name image:tag\n'),  # configuration services
                 SucceededResult(),  # pod update
                 SucceededResult('[{"Parent": "current_parent_id"}]'),  # current image info
                 SucceededResult(),  # update sentinel images
             ],
             expected_command_args=[
                 {'args': ['kubectl', 'config', 'current-context']},
                 {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']},
                 {'args': ['kubectl', 'apply', '--filename=k8s.yml']},
                 {'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': ['kubectl', 'set', 'image', 'kind', 'name=digest']},
                 {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']},
                 {'args': ['docker', 'rmi', 'fabricio-current-kubernetes:k8s', 'current_parent_id;', 'docker', 'tag', 'fabricio-backup-kubernetes:k8s', 'fabricio-current-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-backup-kubernetes:k8s']},
             ],
             expected_compose_file=b'compose.yml',
         ),
         reverted_with_pods_updates=dict(
             init_kwargs=dict(),
             side_effect=[
                 SucceededResult(),  # manager status
                 SucceededResult(json.dumps([{'Config': {
                     'Labels': {
                         'fabricio.configuration': 'Y29tcG9zZS55bWw=',  # compose.yml
                         'fabricio.digests': 'eyJpbWFnZTE6dGFnIjogImRpZ2VzdDEiLCAiaW1hZ2UyOnRhZyI6ICJkaWdlc3QyIn0=',  # {"image1:tag": "digest1", "image2:tag": "digest2"}
                     },
                 }}])),  # image info
                 SucceededResult(),  # configuration deploy
                 SucceededResult('kind1 name1 image1:tag\nkind2 name2 image2:tag'),  # configuration services
                 SucceededResult(),  # pod update
                 SucceededResult(),  # pod update
                 SucceededResult('[{"Parent": "current_parent_id"}]'),  # current image info
                 SucceededResult(),  # update sentinel images
             ],
             expected_command_args=[
                 {'args': ['kubectl', 'config', 'current-context']},
                 {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-backup-kubernetes:k8s']},
                 {'args': ['kubectl', 'apply', '--filename=k8s.yml']},
                 {'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': ['kubectl', 'set', 'image', 'kind1', 'name1=digest1']},
                 {'args': ['kubectl', 'set', 'image', 'kind2', 'name2=digest2']},
                 {'args': ['docker', 'inspect', '--type', 'image', 'fabricio-current-kubernetes:k8s']},
                 {'args': ['docker', 'rmi', 'fabricio-current-kubernetes:k8s', 'current_parent_id;', 'docker', 'tag', 'fabricio-backup-kubernetes:k8s', 'fabricio-current-kubernetes:k8s;', 'docker', 'rmi', 'fabricio-backup-kubernetes:k8s']},
             ],
             expected_compose_file=b'compose.yml',
         ),
     )
     for case, data in cases.items():
         with self.subTest(case=case):
             fab.env.command = '{0}__{1}'.format(self, case)
             put.reset_mock()
             with mock.patch.dict(fab.env, dict(all_hosts=data.get('all_hosts', ['host']))):
                 configuration = kubernetes.Configuration(
                     name='k8s',
                     options={'filename': 'k8s.yml'},
                     **data.get('init_kwargs', {})
                 )
                 side_effects = data.get('side_effect', [])
                 side_effect = self.command_checker(
                     args_parsers=args_parser,
                     expected_args_set=data.get('expected_command_args', []),
                     side_effects=side_effects,
                 )
                 with mock.patch.object(fabricio, 'run', side_effect=side_effect) as run:
                     with mock.patch('six.BytesIO') as compose_file:
                         configuration.revert()
                 self.assertEqual(run.call_count, len(side_effects))
                 expected_compose_file = data.get('expected_compose_file')
                 if expected_compose_file:
                     put.assert_called_once()
                     compose_file.assert_called_once_with(expected_compose_file)
                 else:
                     put.assert_not_called()
Example #7
0
"""

import fabricio

from fabric import api as fab
from fabricio import tasks, kubernetes
from fabricio.misc import AvailableVagrantHosts
from six.moves import filter

hosts = AvailableVagrantHosts(guest_network_interface='eth1')

service = tasks.DockerTasks(
    service=kubernetes.Configuration(
        name='my-service',
        options={
            # `kubectl apply` options
            'filename': 'configuration.yml',
        },
    ),
    hosts=hosts,

    # rollback_command=True,  # show `rollback` command in the list
    # migrate_commands=True,  # show `migrate` and `migrate-back` commands in the list
    # backup_commands=True,  # show `backup` and `restore` commands in the list
    # pull_command=True,  # show `pull` command in the list
    # update_command=True,  # show `update` command in the list
    # revert_command=True,  # show `revert` command in the list
    # destroy_command=True,  # show `destroy` command in the list
)