Skip to content
This repository has been archived by the owner on Sep 12, 2020. It is now read-only.

Commit

Permalink
Adjust white space
Browse files Browse the repository at this point in the history
  • Loading branch information
xbglowx committed Dec 21, 2016
1 parent 032c031 commit aa855cf
Showing 1 changed file with 155 additions and 156 deletions.
311 changes: 155 additions & 156 deletions docker-proper.go
Original file line number Diff line number Diff line change
@@ -1,182 +1,181 @@
package main

import (
"flag"
"log"
"time"
"flag"
"log"
"time"

"github.com/samalba/dockerclient"
"github.com/samalba/dockerclient"
)

var (
addr = flag.String("a", "unix:///var/run/docker.sock", "address of docker daemon")
ageContainer = flag.Duration("ca", 4*7*24*time.Hour, "Max container age")
ageImage = flag.Duration("ia", 4*7*24*time.Hour, "Max images age")
interval = flag.Duration("r", 0, "Run continously in given interval")

dry = flag.Bool("dry", false, "Dry run; do not actually delete")
unsafe = flag.Bool("u", false, "Unsafe; Delete container without FinishedAt field set")
verbose = flag.Bool("v", false, "Be verbose")
now = time.Now()
addr = flag.String("a", "unix:///var/run/docker.sock", "address of docker daemon")
ageContainer = flag.Duration("ca", 4*7*24*time.Hour, "Max container age")
ageImage = flag.Duration("ia", 4*7*24*time.Hour, "Max images age")
interval = flag.Duration("r", 0, "Run continously in given interval")
dry = flag.Bool("dry", false, "Dry run; do not actually delete")
unsafe = flag.Bool("u", false, "Unsafe; Delete container without FinishedAt field set")
verbose = flag.Bool("v", false, "Be verbose")
now = time.Now()
)

func debug(fs string, args ...interface{}) {
if *verbose {
log.Printf(fs, args...)
}
if *verbose {
log.Printf(fs, args...)
}
}

func main() {
flag.Parse()

for {
client, err := dockerclient.NewDockerClient(*addr, nil)
if err != nil {
log.Fatal(err)
}

expiredContainers, err := getExpiredContainers(client)
if err != nil {
log.Fatal(err)
}
if err := removeContainers(client, expiredContainers); err != nil {
log.Fatal(err)
}

if err := removeImages(client); err != nil {
log.Fatal(err)
}

if *interval == 0 {
break
}
log.Printf("Sleeping for %s", *interval)
time.Sleep(*interval)
}
flag.Parse()

for {
client, err := dockerclient.NewDockerClient(*addr, nil)
if err != nil {
log.Fatal(err)
}

expiredContainers, err := getExpiredContainers(client)
if err != nil {
log.Fatal(err)
}
if err := removeContainers(client, expiredContainers); err != nil {
log.Fatal(err)
}

if err := removeImages(client); err != nil {
log.Fatal(err)
}

if *interval == 0 {
break
}
log.Printf("Sleeping for %s", *interval)
time.Sleep(*interval)
}
}

func getExpiredContainers(client *dockerclient.DockerClient) (expiredContainers []*dockerclient.ContainerInfo, err error) {
containers, err := client.ListContainers(true, false, "") // true = all containers
if err != nil {
return nil, err
}

usedVolumeContainers := map[string]int{}
usedImages := map[string]int{}
oldContainers := []*dockerclient.ContainerInfo{}
for _, c := range containers {
debug("< container: %s", c.Id)
container, err := client.InspectContainer(c.Id)
if err != nil {
debug(" + Couldn't inspect container %s, skipping: %s", c.Id, err)
continue
}

// Increment reference counter refering to how many containers use volume container and image
if len(container.HostConfig.VolumesFrom) > 0 {
for _, vc := range container.HostConfig.VolumesFrom {
usedVolumeContainers[vc]++
}
}
debug(" + Container %s uses image %s", c.Id, container.Image)
usedImages[container.Image]++

if container.State.Running {
debug(" + Container is still running")
continue
}
debug(" + not running")

if container.State.FinishedAt == time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) && !*unsafe {
debug(" + Container %s has empty FinishedAt field, skipping", c.Id)
continue
}
created, err := time.Parse(time.RFC3339, container.Created)
if err != nil {
return nil, err
}
debug(" + Container and image threshold %s", now.Add(-*ageContainer))
if created.After(now.Add(-*ageContainer)) {
debug(" + Creation time is not old enough: %s", created)
continue
}
debug(" + Creation time is older than %s", *ageContainer)
if container.State.FinishedAt.After(now.Add(-*ageContainer)) {
debug(" + Exit time is not old enough: %s", container.State.FinishedAt)
continue
}
debug(" + Exit time is older than %s", *ageContainer)

// Decrement reference counter for old containers
if len(container.HostConfig.VolumesFrom) > 0 {
for _, vc := range container.HostConfig.VolumesFrom {
usedVolumeContainers[vc]--
}
}
usedImages[container.Image]--

oldContainers = append(oldContainers, container)
}

for _, c := range oldContainers {
name := c.Name[1:] // Remove leading /
if usedVolumeContainers[name] > 0 {
continue
}
expiredContainers = append(expiredContainers, c)
}
log.Printf("Found %d expired containers", len(expiredContainers))

return expiredContainers, nil
containers, err := client.ListContainers(true, false, "") // true = all containers
if err != nil {
return nil, err
}

usedVolumeContainers := map[string]int{}
usedImages := map[string]int{}
oldContainers := []*dockerclient.ContainerInfo{}
for _, c := range containers {
debug("< container: %s", c.Id)
container, err := client.InspectContainer(c.Id)
if err != nil {
debug(" + Couldn't inspect container %s, skipping: %s", c.Id, err)
continue
}

// Increment reference counter refering to how many containers use volume container and image
if len(container.HostConfig.VolumesFrom) > 0 {
for _, vc := range container.HostConfig.VolumesFrom {
usedVolumeContainers[vc]++
}
}
debug(" + Container %s uses image %s", c.Id, container.Image)
usedImages[container.Image]++

if container.State.Running {
debug(" + Container is still running")
continue
}
debug(" + not running")

if container.State.FinishedAt == time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) && !*unsafe {
debug(" + Container %s has empty FinishedAt field, skipping", c.Id)
continue
}
created, err := time.Parse(time.RFC3339, container.Created)
if err != nil {
return nil, err
}
debug(" + Container and image threshold %s", now.Add(-*ageContainer))
if created.After(now.Add(-*ageContainer)) {
debug(" + Creation time is not old enough: %s", created)
continue
}
debug(" + Creation time is older than %s", *ageContainer)
if container.State.FinishedAt.After(now.Add(-*ageContainer)) {
debug(" + Exit time is not old enough: %s", container.State.FinishedAt)
continue
}
debug(" + Exit time is older than %s", *ageContainer)

// Decrement reference counter for old containers
if len(container.HostConfig.VolumesFrom) > 0 {
for _, vc := range container.HostConfig.VolumesFrom {
usedVolumeContainers[vc]--
}
}
usedImages[container.Image]--

oldContainers = append(oldContainers, container)
}

for _, c := range oldContainers {
name := c.Name[1:] // Remove leading /
if usedVolumeContainers[name] > 0 {
continue
}
expiredContainers = append(expiredContainers, c)
}
log.Printf("Found %d expired containers", len(expiredContainers))

return expiredContainers, nil
}

// Search for all images that have expired based on operator input and try to
// remove them. If they are currently being used, the remvoal will fail, but that
// is OK.
func removeImages(client *dockerclient.DockerClient) error {
expiredImages := []*dockerclient.Image{}
images, err := client.ListImages(true)
if err != nil {
return err
}

for _, image := range images {
debug("< image id: %s", image.Id)
ctime := time.Unix(image.Created, 0)
if ctime.After(now.Add(-*ageImage)) {
continue
}
debug(" + older than %s", *ageImage)
expiredImages = append(expiredImages, image)
}

log.Printf("Found %d expired images", len(expiredImages))

for _, image := range expiredImages {
log.Print("rmi ", image.Id)
if !*dry {
if _, err := client.RemoveImage(image.Id, false); err != nil {
debug("Couldn't remove image with ID %s. Let's try to remove the same image, but this time using repo tags: %s", image.Id, err)
for _, repoTag := range image.RepoTags {
log.Print("rmi ", repoTag)
if _, err := client.RemoveImage(repoTag, false); err != nil {
debug("Couldn't remove image with repo tag %s: %s", repoTag, err)
}
}
}
}
}
return nil
expiredImages := []*dockerclient.Image{}
images, err := client.ListImages(true)
if err != nil {
return err
}

for _, image := range images {
debug("< image id: %s", image.Id)
ctime := time.Unix(image.Created, 0)
if ctime.After(now.Add(-*ageImage)) {
continue
}
debug(" + older than %s", *ageImage)
expiredImages = append(expiredImages, image)
}

log.Printf("Found %d expired images", len(expiredImages))

for _, image := range expiredImages {
log.Print("rmi ", image.Id)
if !*dry {
if _, err := client.RemoveImage(image.Id, false); err != nil {
debug("Couldn't remove image with ID %s. Let's try to remove the same image, but this time using repo tags: %s", image.Id, err)
for _, repoTag := range image.RepoTags {
log.Print("rmi ", repoTag)
if _, err := client.RemoveImage(repoTag, false); err != nil {
debug("Couldn't remove image with repo tag %s: %s", repoTag, err)
}
}
}
}
}
return nil
}

func removeContainers(client *dockerclient.DockerClient, containers []*dockerclient.ContainerInfo) error {
for _, container := range containers {
log.Printf("rm %s (%s)", container.Id, container.Name)
if !*dry {
if err := client.RemoveContainer(container.Id, false, false); err != nil {
debug("Couldn't remove container: %s", err)
}
}
}
return nil
for _, container := range containers {
log.Printf("rm %s (%s)", container.Id, container.Name)
if !*dry {
if err := client.RemoveContainer(container.Id, false, false); err != nil {
debug("Couldn't remove container: %s", err)
}
}
}
return nil
}

0 comments on commit aa855cf

Please sign in to comment.