Passed
Push — master ( 61e6a6...28b40d )
by Emmanuel
07:42
created

stakkr.docker_clean.main()   A

Complexity

Conditions 2

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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