Преглед на файлове

add sizes in images and containers

Victor Vieux преди 12 години
родител
ревизия
a91b710961
променени са 8 файла, в които са добавени 105 реда и са изтрити 11 реда
  1. 10 6
      api_params.go
  2. 1 1
      api_test.go
  3. 9 4
      commands.go
  4. 24 0
      container.go
  5. 9 0
      graph.go
  6. 24 0
      image.go
  7. 5 0
      server.go
  8. 23 0
      utils.go

+ 10 - 6
api_params.go

@@ -11,6 +11,8 @@ type ApiImages struct {
 	Tag        string `json:",omitempty"`
 	Id         string
 	Created    int64 `json:",omitempty"`
+	Size       int64
+	ParentSize int64
 }
 
 type ApiInfo struct {
@@ -24,12 +26,14 @@ type ApiInfo struct {
 }
 
 type ApiContainers struct {
-	Id      string
-	Image   string `json:",omitempty"`
-	Command string `json:",omitempty"`
-	Created int64  `json:",omitempty"`
-	Status  string `json:",omitempty"`
-	Ports   string `json:",omitempty"`
+	Id         string
+	Image      string `json:",omitempty"`
+	Command    string `json:",omitempty"`
+	Created    int64  `json:",omitempty"`
+	Status     string `json:",omitempty"`
+	Ports      string `json:",omitempty"`
+	SizeRw     int64
+	SizeRootFs int64
 }
 
 type ApiSearch struct {

+ 1 - 1
api_test.go

@@ -1194,7 +1194,7 @@ func TestDeleteContainers(t *testing.T) {
 
 func TestDeleteImages(t *testing.T) {
 	//FIXME: Implement this test
-	t.Skip("Test not implemented")
+	t.Log("Test not implemented")
 }
 
 // Mocked types for tests

+ 9 - 4
commands.go

@@ -728,12 +728,12 @@ func CmdImages(args ...string) error {
 
 		w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
 		if !*quiet {
-			fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED")
+			fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED\tSIZE")
 		}
 
 		for _, out := range outs {
 			if !*quiet {
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\n", out.Repository, out.Tag, out.Id, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s (virtual %s)\n", out.Repository, out.Tag, out.Id, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), HumanSize(out.Size), HumanSize(out.ParentSize))
 			} else {
 				fmt.Fprintln(w, out.Id)
 			}
@@ -794,12 +794,17 @@ func CmdPs(args ...string) error {
 	}
 	w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
 	if !*quiet {
-		fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS")
+		fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tSIZE")
 	}
 
 	for _, out := range outs {
 		if !*quiet {
-			fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", out.Id, out.Image, out.Command, out.Status, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
+			fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\t", out.Id, out.Image, out.Command, out.Status, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
+			if out.SizeRootFs > 0 {
+				fmt.Fprintf(w, "%s (virtual %s)\n", HumanSize(out.SizeRw), HumanSize(out.SizeRootFs))
+			} else {
+				fmt.Fprintf(w, "%s\n", HumanSize(out.SizeRw))
+			}
 		} else {
 			fmt.Fprintln(w, out.Id)
 		}

+ 24 - 0
container.go

@@ -11,6 +11,7 @@ import (
 	"os"
 	"os/exec"
 	"path"
+	"path/filepath"
 	"sort"
 	"strconv"
 	"strings"
@@ -879,3 +880,26 @@ func validateId(id string) error {
 	}
 	return nil
 }
+
+// GetSize, return real size, virtual size
+func (container *Container) GetSize() (int64, int64) {
+	var sizeRw, sizeRootfs int64
+
+	filepath.Walk(container.rwPath(), func(path string, fileInfo os.FileInfo, err error) error {
+		if fileInfo != nil {
+			sizeRw += fileInfo.Size()
+		}
+		return nil
+	})
+
+	_, err := os.Stat(container.RootfsPath())
+	if err == nil {
+		filepath.Walk(container.RootfsPath(), func(path string, fileInfo os.FileInfo, err error) error {
+			if fileInfo != nil {
+				sizeRootfs += fileInfo.Size()
+			}
+			return nil
+		})
+	}
+	return sizeRw, sizeRootfs
+}

+ 9 - 0
graph.go

@@ -89,6 +89,15 @@ func (graph *Graph) Get(name string) (*Image, error) {
 	if img.Id != id {
 		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id)
 	}
+	if img.Size == 0 {
+		root, err := img.root()
+		if err != nil {
+			return nil, err
+		}
+		if err := StoreSize(img, root); err != nil {
+			return nil, err
+		}
+	}
 	img.graph = graph
 	graph.lockSumMap.Lock()
 	defer graph.lockSumMap.Unlock()

+ 24 - 0
image.go

@@ -12,6 +12,7 @@ import (
 	"os"
 	"os/exec"
 	"path"
+	"path/filepath"
 	"strings"
 	"time"
 )
@@ -27,6 +28,8 @@ type Image struct {
 	Author          string    `json:"author,omitempty"`
 	Config          *Config   `json:"config,omitempty"`
 	graph           *Graph
+	Size            int64
+	ParentSize      int64
 }
 
 func LoadImage(root string) (*Image, error) {
@@ -93,6 +96,18 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error {
 	if err := Untar(layerData, layer); err != nil {
 		return err
 	}
+
+	return StoreSize(img, root)
+}
+
+func StoreSize(img *Image, root string) error {
+	layer := layerPath(root)
+
+	filepath.Walk(layer, func(path string, fileInfo os.FileInfo, err error) error {
+		img.Size += fileInfo.Size()
+		return nil
+	})
+
 	// Store the json ball
 	jsonData, err := json.Marshal(img)
 	if err != nil {
@@ -359,3 +374,12 @@ func (img *Image) Checksum() (string, error) {
 
 	return hash, nil
 }
+
+func (img *Image) getVirtualSize(size int64) int64 {
+	parentImage, err := img.GetParent()
+	if err != nil || parentImage == nil {
+		return size
+	}
+	size += parentImage.Size
+	return parentImage.getVirtualSize(size)
+}

+ 5 - 0
server.go

@@ -164,6 +164,8 @@ func (srv *Server) Images(all, only_ids bool, filter string) ([]ApiImages, error
 				out.Tag = tag
 				out.Id = TruncateId(id)
 				out.Created = image.Created.Unix()
+				out.Size = image.Size
+				out.ParentSize = image.getVirtualSize(0)
 			} else {
 				out.Id = image.ShortId()
 			}
@@ -179,6 +181,8 @@ func (srv *Server) Images(all, only_ids bool, filter string) ([]ApiImages, error
 				out.Tag = "<none>"
 				out.Id = TruncateId(id)
 				out.Created = image.Created.Unix()
+				out.Size = image.Size
+				out.ParentSize = image.getVirtualSize(0)
 			} else {
 				out.Id = image.ShortId()
 			}
@@ -280,6 +284,7 @@ func (srv *Server) Containers(all, trunc_cmd, only_ids bool, n int, since, befor
 			c.Created = container.Created.Unix()
 			c.Status = container.State.String()
 			c.Ports = container.NetworkSettings.PortMappingHuman()
+			c.SizeRw, c.SizeRootFs = container.GetSize()
 		}
 		retContainers = append(retContainers, c)
 	}

+ 23 - 0
utils.go

@@ -16,6 +16,7 @@ import (
 	"os/signal"
 	"path/filepath"
 	"runtime"
+	_ "strconv"
 	"strings"
 	"sync"
 	"time"
@@ -133,6 +134,28 @@ func HumanDuration(d time.Duration) string {
 	return fmt.Sprintf("%d years", d.Hours()/24/365)
 }
 
+// HumanSize returns a human-readabla approximation of a size
+// (eg. "44K", "17M")
+func HumanSize(size int64) string {
+	i := 0
+	var sizef float64
+	sizef = float64(size)
+	units := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
+	for sizef > 1024.0 {
+		sizef = sizef / 1024.0
+		i++
+	}
+	return fmt.Sprintf("%.*f %s", i, sizef, units[i])
+	// sprintf(buf, "%.*f %s", i, size, units[i]);
+	// if size/1024/1024 > 1000 {
+	// 	return strconv.FormatFloat((float64)(size/1024/1024), 'f', 2, 32) + "G"
+	// }
+	// if size/1024 > 1024 {
+	// 	return strconv.FormatInt(size/1024/1024, 10) + "M"
+	// }
+	// return strconv.FormatInt(size/1024, 10) + "K"
+}
+
 func Trunc(s string, maxlen int) string {
 	if len(s) <= maxlen {
 		return s