diff --git a/pkg/cloudcfg/resource_printer.go b/pkg/cloudcfg/resource_printer.go new file mode 100644 index 00000000000..aa3382d72b3 --- /dev/null +++ b/pkg/cloudcfg/resource_printer.go @@ -0,0 +1,206 @@ +package cloudcfg + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "strings" + "text/tabwriter" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "gopkg.in/v1/yaml" +) + +type ResourcePrinter interface { + Print(string, io.Writer) error +} + +type IdentityPrinter struct{} + +func (i *IdentityPrinter) Print(data string, w io.Writer) error { + _, err := io.Copy(w, bytes.NewBufferString(data)) + return err +} + +type YAMLPrinter struct{} + +func (y *YAMLPrinter) Print(data string, w io.Writer) error { + var obj interface{} + if err := json.Unmarshal([]byte(data), &obj); err != nil { + return err + } + output, err := yaml.Marshal(obj) + if err != nil { + return err + } + _, err = fmt.Fprint(w, string(output)) + return err +} + +type HumanReadablePrinter struct{} + +var taskColumns = []string{"Name", "Image(s)", "Host", "Labels"} +var replicationControllerColumns = []string{"Name", "Image(s)", "Label Query", "Replicas"} +var serviceColumns = []string{"Name", "Label Query", "Port"} + +func (h *HumanReadablePrinter) unknown(data string, w io.Writer) error { + _, err := fmt.Fprintf(w, "Unknown object: %s", data) + return err +} + +func (h *HumanReadablePrinter) printHeader(columnNames []string, w io.Writer) error { + if _, err := fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t")); err != nil { + return err + } + var lines []string + for _, _ = range columnNames { + lines = append(lines, "----------") + } + _, err := fmt.Fprintf(w, "%s\n", strings.Join(lines, "\t")) + return err +} + +func (h *HumanReadablePrinter) makeImageList(manifest api.ContainerManifest) string { + var images []string + for _, container := range manifest.Containers { + images = append(images, container.Image) + } + return strings.Join(images, ",") +} + +func (h *HumanReadablePrinter) makeLabelsList(labels map[string]string) string { + var vals []string + for key, value := range labels { + vals = append(vals, fmt.Sprintf("%s=%s", key, value)) + } + return strings.Join(vals, ",") +} + +func (h *HumanReadablePrinter) printTask(task api.Task, w io.Writer) error { + _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", + task.ID, h.makeImageList(task.DesiredState.Manifest), task.CurrentState.Host, h.makeLabelsList(task.Labels)) + return err +} + +func (h *HumanReadablePrinter) printTaskList(taskList api.TaskList, w io.Writer) error { + for _, task := range taskList.Items { + if err := h.printTask(task, w); err != nil { + return err + } + } + return nil +} + +func (h *HumanReadablePrinter) printReplicationController(ctrl api.ReplicationController, w io.Writer) error { + _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n", + ctrl.ID, h.makeImageList(ctrl.DesiredState.TaskTemplate.DesiredState.Manifest), h.makeLabelsList(ctrl.DesiredState.ReplicasInSet), ctrl.DesiredState.Replicas) + return err +} + +func (h *HumanReadablePrinter) printReplicationControllerList(list api.ReplicationControllerList, w io.Writer) error { + for _, ctrl := range list.Items { + if err := h.printReplicationController(ctrl, w); err != nil { + return err + } + } + return nil +} + +func (h *HumanReadablePrinter) printService(svc api.Service, w io.Writer) error { + _, err := fmt.Fprintf(w, "%s\t%s\t%d\n", svc.ID, h.makeLabelsList(svc.Labels), svc.Port) + return err +} + +func (h *HumanReadablePrinter) printServiceList(list api.ServiceList, w io.Writer) error { + for _, svc := range list.Items { + if err := h.printService(svc, w); err != nil { + return err + } + } + return nil +} + +func (h *HumanReadablePrinter) extractObject(data, kind string) (interface{}, error) { + // TODO: I think this can be replaced with some reflection and a map[string]type + switch kind { + case "cluster#task": + var obj api.Task + if err := json.Unmarshal([]byte(data), &obj); err != nil { + return nil, err + } + return obj, nil + case "cluster#taskList": + var list api.TaskList + if err := json.Unmarshal([]byte(data), &list); err != nil { + return nil, err + } + return list, nil + case "cluster#replicationController": + var ctrl api.ReplicationController + if err := json.Unmarshal([]byte(data), &ctrl); err != nil { + return nil, err + } + return ctrl, nil + case "cluster#replicationControllerList": + var list api.ReplicationControllerList + if err := json.Unmarshal([]byte(data), &list); err != nil { + return nil, err + } + return list, nil + case "cluster#service": + var ctrl api.Service + if err := json.Unmarshal([]byte(data), &ctrl); err != nil { + return nil, err + } + return ctrl, nil + case "cluster#serviceList": + var list api.ServiceList + if err := json.Unmarshal([]byte(data), &list); err != nil { + return nil, err + } + return list, nil + default: + return nil, fmt.Errorf("Unknown kind: %s", kind) + } +} + +func (h *HumanReadablePrinter) Print(data string, output io.Writer) error { + w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0) + defer w.Flush() + var obj interface{} + if err := json.Unmarshal([]byte(data), &obj); err != nil { + return err + } + + if _, contains := obj.(map[string]interface{})["kind"]; !contains { + return fmt.Errorf("Unexpected object with no 'kind' field: %s", data) + } + kind := (obj.(map[string]interface{})["kind"]).(string) + obj, err := h.extractObject(data, kind) + if err != nil { + return err + } + switch obj.(type) { + case api.Task: + h.printHeader(taskColumns, w) + return h.printTask(obj.(api.Task), w) + case api.TaskList: + h.printHeader(taskColumns, w) + return h.printTaskList(obj.(api.TaskList), w) + case api.ReplicationController: + h.printHeader(replicationControllerColumns, w) + return h.printReplicationController(obj.(api.ReplicationController), w) + case api.ReplicationControllerList: + h.printHeader(replicationControllerColumns, w) + return h.printReplicationControllerList(obj.(api.ReplicationControllerList), w) + case api.Service: + h.printHeader(serviceColumns, w) + return h.printService(obj.(api.Service), w) + case api.ServiceList: + h.printHeader(serviceColumns, w) + return h.printServiceList(obj.(api.ServiceList), w) + default: + return h.unknown(data, w) + } +}