github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/metadata/diag.go (about)

     1  /*
     2  Copyright 2018 Mirantis
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package metadata
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"strings"
    24  
    25  	"github.com/ghodss/yaml"
    26  
    27  	"github.com/Mirantis/virtlet/pkg/diag"
    28  	"github.com/Mirantis/virtlet/pkg/metadata/types"
    29  )
    30  
    31  const (
    32  	indentStr = "  "
    33  )
    34  
    35  type metadataDumper struct {
    36  	store  Store
    37  	out    io.Writer
    38  	indent int
    39  }
    40  
    41  func newMetadataDumper(store Store, out io.Writer) *metadataDumper {
    42  	return &metadataDumper{store: store, out: out}
    43  }
    44  
    45  func (d *metadataDumper) withAddedIndent(toCall func()) {
    46  	d.indent++
    47  	defer func() {
    48  		d.indent--
    49  	}()
    50  	toCall()
    51  }
    52  
    53  func (d *metadataDumper) indentString() string {
    54  	return strings.Repeat(indentStr, d.indent)
    55  }
    56  
    57  func (d *metadataDumper) outputYaml(o interface{}) {
    58  	out, err := yaml.Marshal(o)
    59  	if err != nil {
    60  		fmt.Fprintf(d.out, "<error marshalling the object: %v", err)
    61  	}
    62  	indentStr := d.indentString()
    63  	for _, l := range strings.Split(string(out), "\n") {
    64  		if l != "" {
    65  			l = indentStr + l
    66  		}
    67  		fmt.Fprintln(d.out, l)
    68  	}
    69  }
    70  
    71  func (d *metadataDumper) output(format string, args ...interface{}) {
    72  	fmt.Fprintf(d.out, d.indentString()+format+"\n", args...)
    73  }
    74  
    75  func (d *metadataDumper) outputError(description string, err error) {
    76  	d.output("<error: %s: %v>", description, err)
    77  }
    78  
    79  func (d *metadataDumper) dump() {
    80  	d.output("Sandboxes:")
    81  	sandboxes, err := d.store.ListPodSandboxes(nil)
    82  	switch {
    83  	case err != nil:
    84  		d.outputError("can't list sandboxes", err)
    85  	case len(sandboxes) == 0:
    86  		d.output("no sandboxes found")
    87  	default:
    88  		d.withAddedIndent(func() {
    89  			for _, smeta := range sandboxes {
    90  				if sinfo, err := smeta.Retrieve(); err != nil {
    91  					d.outputError("can't retrieve sandbox", err)
    92  				} else if err := d.dumpSandbox(smeta.GetID(), sinfo); err != nil {
    93  					d.outputError("dumping sandbox", err)
    94  				}
    95  			}
    96  		})
    97  	}
    98  
    99  	d.output("Images:")
   100  	images, err := d.store.ImagesInUse()
   101  	switch {
   102  	case err != nil:
   103  		d.outputError("can't list images", err)
   104  	case len(images) == 0:
   105  		d.output("no images found")
   106  	default:
   107  		d.withAddedIndent(func() {
   108  			for image := range images {
   109  				d.output(image)
   110  			}
   111  		})
   112  	}
   113  }
   114  
   115  func (d *metadataDumper) dumpSandbox(podID string, sandbox *types.PodSandboxInfo) error {
   116  	d.output("Sandbox ID: %v", podID)
   117  	d.withAddedIndent(func() {
   118  		d.outputYaml(sandbox)
   119  
   120  		d.output("Containers:")
   121  		containers, err := d.store.ListPodContainers(podID)
   122  		switch {
   123  		case err != nil:
   124  			d.outputError("can't retrieve the list of containers", err)
   125  		case len(containers) == 0:
   126  			d.output("no containers found")
   127  		default:
   128  			d.withAddedIndent(func() {
   129  				for _, cmeta := range containers {
   130  					d.output("Container ID: %s", cmeta.GetID())
   131  					if cinfo, err := cmeta.Retrieve(); err != nil {
   132  						d.outputError("can't retrieve container metadata", err)
   133  					} else {
   134  						d.withAddedIndent(func() { d.outputYaml(cinfo) })
   135  					}
   136  				}
   137  			})
   138  		}
   139  	})
   140  
   141  	return nil
   142  }
   143  
   144  // GetMetadataDumpSource returns a Source that dumps Virtlet metadata.
   145  func GetMetadataDumpSource(store Store) diag.Source {
   146  	return diag.NewSimpleTextSource("txt", func() (string, error) {
   147  		var out bytes.Buffer
   148  		dumper := newMetadataDumper(store, &out)
   149  		dumper.dump()
   150  		return out.String(), nil
   151  	})
   152  }