Passed
Push — master ( e8584f...303446 )
by Emmanuel
04:55
created

docker_clean.main()   A

Complexity

Conditions 2

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 4.8094

Importance

Changes 0
Metric Value
cc 2
eloc 10
nop 0
dl 0
loc 19
ccs 1
cts 9
cp 0.1111
crap 4.8094
rs 9.9
c 0
b 0
f 0
1
#!/usr/bin/env python
2
# coding: utf-8
3 1
"""
4
Docker Clean command.
5
6
Clean unused containers, images, volumes and networks.
7
That saves a lot of space ...
8
"""
9
10 1
import sys
11 1
from subprocess import check_output, CalledProcessError, STDOUT
12 1
import click
13 1
import humanfriendly
14 1
from stakkr.docker_actions import get_client as get_docker_client
15
16
17 1
@click.command(help="""Clean Docker containers, images, volumes and networks
18
that are not in use""", name="docker-clean")
19 1
@click.option('--force', '-f', help="Do it", is_flag=True)
20 1
@click.option('--containers/--no-containers', '-c/', help="Remove containers", is_flag=True, default=True)
21 1
@click.option('--images/--no-images', '-i/', help="Remove images", is_flag=True, default=True)
22 1
@click.option('--volumes/--no-volumes', '-V/', help="Remove volumes", is_flag=True, default=True)
23 1
@click.option('--networks/--no-networks', '-n/', help="Remove networks", is_flag=True, default=True)
24 1
@click.option('--verbose', '-v', help="Display more information about what is removed",
25
              is_flag=True)
26 1
def clean(force: bool, containers: bool, images: bool, volumes: bool, networks: bool, verbose: bool):
27
    """See command help."""
28 1
    if containers is True:
29 1
        click.secho('Cleaning Docker stopped containers:', fg='green')
30 1
        remove_containers(force, verbose)
31 1
    if images is True:
32 1
        click.secho('Cleaning Docker unused images:', fg='green')
33 1
        remove_images(force, verbose)
34 1
    if volumes is True:
35 1
        click.secho('Cleaning Docker unused volumes:', fg='green')
36 1
        remove_volumes(force, verbose)
37 1
    if networks is True:
38 1
        click.secho('Cleaning Docker unused networks:', fg='green')
39 1
        remove_networks(force, verbose)
40
41
42 1 View Code Duplication
def remove_containers(force: bool, verbose: bool):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
43
    """Remove exited containers."""
44 1
    stopped_containers = get_docker_client().containers.list(filters={'status': 'exited'})
45 1
    if len(stopped_containers) is 0:
46 1
        print('  No exited container to remove')
47 1
        return
48
49 1
    if force is False:
50
        click.secho("  --force is not set so I won't do anything", fg='red')
51
        return
52
53 1
    res = get_docker_client().containers.prune()
54 1
    cts = len(res['ContainersDeleted'])
55 1
    space = humanfriendly.format_size(res['SpaceReclaimed'])
56 1
    click.echo('  Removed {} exited container(s), saved {}'.format(cts, space))
57
58
59 1 View Code Duplication
def remove_images(force: bool, verbose: bool):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
60
    """Remove unused images."""
61 1
    if force is False:
62 1
        click.secho("  --force is not set so I won't do anything", fg='red')
63 1
        return
64
65 1
    res = get_docker_client().images.prune(filters={'dangling': False})
66 1
    if res['ImagesDeleted'] is None:
67
        print('  No image to remove')
68
        return
69
70 1
    images = len(res['ImagesDeleted'])
71 1
    space = humanfriendly.format_size(res['SpaceReclaimed'])
72 1
    click.echo('  Removed {} images(s), saved {}'.format(images, space))
73
74
75 1
def remove_networks(force: bool, verbose: bool):
76
    """Remove unused networks."""
77 1
    if force is False:
78 1
        click.secho("  --force is not set so I won't do anything", fg='red')
79 1
        return
80
81 1
    res = get_docker_client().networks.prune()
82 1
    if res['NetworksDeleted'] is None:
83
        print('  No network to remove')
84
        return
85
86 1
    networks = len(res['NetworksDeleted'])
87 1
    click.echo('  Removed {} network(s)'.format(networks))
88
89
90 1
def remove_volumes(force: bool, verbose: bool):
91
    """Remove unused volumes."""
92 1
    if force is False:
93 1
        click.secho("  --force is not set so I won't do anything", fg='red')
94 1
        return
95
96 1
    res = get_docker_client().volumes.prune()
97 1
    if len(res['VolumesDeleted']) is 0:
98 1
        print('  No volume to remove')
99 1
        return
100
101 1
    volumes = len(res['VolumesDeleted'])
102 1
    space = humanfriendly.format_size(res['SpaceReclaimed'])
103 1
    click.echo('  Removed {} volume(s), saved {}'.format(volumes, space))
104
105
106 1
def main():
107
    """Generate the CLI."""
108
    try:
109
        clean()
110
    except Exception as error:
111
        msg = click.style(r""" ______ _____  _____   ____  _____
112
|  ____|  __ \|  __ \ / __ \|  __ \
113
| |__  | |__) | |__) | |  | | |__) |
114
|  __| |  _  /|  _  /| |  | |  _  /
115
| |____| | \ \| | \ \| |__| | | \ \
116
|______|_|  \_\_|  \_\\____/|_|  \_\
117
118
""", fg='yellow')
119
        msg += click.style('{}'.format(error), fg='red')
120
121
        click.echo(msg)
122
        click.echo()
123
        # raise error
124
        sys.exit(1)
125
126
127 1
if __name__ == '__main__':
128
    main()
129