Commit eba4c59a authored by Matt Butcher's avatar Matt Butcher
Browse files

Merge pull request #632 from technosophos/feat/helm-list

feat(helm, tiller): add release listings
parents 1d0f43b0 e869c36c
main Release add-codeql dependabot/go_modules/github.com/docker/distribution-2.8.2incompatible dependabot/go_modules/github.com/lib/pq-1.10.9 dependabot/go_modules/github.com/rubenv/sql-migrate-1.4.0 dependabot/go_modules/golang.org/x/crypto-0.9.0 dependabot/go_modules/golang.org/x/term-0.8.0 dependabot/go_modules/k8s.io/klog/v2-2.100.1 dev-v2 feat-v3/event-emitter-lua kube-update-test release-2.0 release-2.1 release-2.10 release-2.11 release-2.12 release-2.13 release-2.14 release-2.15 release-2.16 release-2.17 release-2.2 release-2.3 release-2.4 release-2.5 release-2.6 release-2.7 release-2.8 release-2.9 release-3.0 release-3.1 release-3.10 release-3.11 release-3.12 release-3.2 release-3.3 release-3.4 release-3.5 release-3.6 release-3.6.1 release-3.6.2 release-3.7 release-3.8 release-3.9 release-v3.0.0-beta.4 v3.12.0 v3.12.0-rc.1 v3.12.0-dev.1 v3.11.3 v3.11.2 v3.11.1 v3.11.0 v3.11.0-rc.2 v3.11.0-rc.1 v3.10.3 v3.10.2 v3.10.1 v3.10.0 v3.10.0-rc.1 v3.9.4 v3.9.3 v3.9.2 v3.9.1 v3.9.0 v3.9.0-rc.1 v3.8.2 v3.8.1 v3.8.0 v3.8.0-rc.2 v3.8.0-rc.1 v3.7.2 v3.7.1 v3.7.0 v3.7.0-rc.3 v3.7.0-rc.2 v3.7.0-rc.1 v3.6.3 v3.6.2 v3.6.1 v3.6.0 v3.6.0-rc.1 v3.5.4 v3.5.3 v3.5.2 v3.5.1 v3.5.0 v3.5.0-rc.2 v3.5.0-rc.1 v3.4.2 v3.4.1 v3.4.0 v3.4.0-rc.1 v3.3.4 v3.3.3 v3.3.2 v3.3.1 v3.3.0 v3.3.0-rc.2 v3.3.0-rc.1 v3.2.4 v3.2.3 v3.2.2 v3.2.1 v3.2.0 v3.2.0-rc.1 v3.1.3 v3.1.2 v3.1.1 v3.1.0 v3.1.0-rc.3 v3.1.0-rc.2 v3.1.0-rc.1 v3.0.3 v3.0.2 v3.0.1 v3.0.0 v3.0.0-rc.4 v3.0.0-rc.3 v3.0.0-rc.2 v3.0.0-rc.1 v3.0.0-beta.5 v3.0.0-beta.4 v3.0.0-beta.3 v3.0.0-beta.2 v3.0.0-beta.1 v3.0.0-alpha.2 v3.0.0-alpha.1 v2.17.0 v2.17.0-rc.1 v2.16.12 v2.16.11 v2.16.10 v2.16.9 v2.16.8 v2.16.7 v2.16.6 v2.16.5 v2.16.4 v2.16.3 v2.16.2 v2.16.1 v2.16.0 v2.16.0-rc.2 v2.16.0-rc.1 v2.15.2 v2.15.1 v2.15.0 v2.15.0-rc.2 v2.15.0-rc.1 v2.14.3 v2.14.2 v2.14.1 v2.14.0 v2.14.0-rc.2 v2.14.0-rc.1 v2.13.1 v2.13.1-rc.1 v2.13.0 v2.13.0-rc.2 v2.13.0-rc.1 v2.12.3 v2.12.2 v2.12.1 v2.12.0 v2.12.0-rc.2 v2.12.0-rc.1 v2.11.0 v2.11.0-rc.4 v2.11.0-rc.3 v2.11.0-rc.2 v2.11.0-rc.1 v2.10.0 v2.10.0-rc.3 v2.10.0-rc.2 v2.10.0-rc.1 v2.9.1 v2.9.0 v2.9.0-rc5 v2.9.0-rc4 v2.9.0-rc3 v2.9.0-rc2 v2.9.0-rc1 v2.8.2 v2.8.2-rc1 v2.8.1 v2.8.0 v2.8.0-rc.1 v2.7.2 v2.7.1 v2.7.0 v2.7.0-rc1 v2.6.2 v2.6.1 v2.6.0 v2.5.1 v2.5.0 v2.4.2 v2.4.1 v2.4.0 v2.3.1 v2.3.0 v2.2.3 v2.2.2 v2.2.1 v2.2.0 v2.1.3 v2.1.2 v2.1.1 v2.1.0 v2.0.2 v2.0.1 v2.0.0 v2.0.0-rc.2 v2.0.0-rc.1 v2.0.0-beta.2 v2.0.0-beta.1 v2.0.0-alpha.5 v2.0.0-alpha.4 v2.0.0-alpha.3 v2.0.0-alpha.2 v2.0.0-alpha.1
No related merge requests found
Showing with 210 additions and 9 deletions
+210 -9
......@@ -54,12 +54,13 @@ func runInstall(cmd *cobra.Command, args []string) error {
// Might be friendly to wrap our proto model with pretty-printers.
//
func printRelease(rel *release.Release) {
if rel == nil {
return
}
fmt.Printf("release.name: %s\n", rel.Name)
if verbose {
if rel != nil {
fmt.Printf("release.name: %s\n", rel.Name)
fmt.Printf("release.info: %s\n", rel.GetInfo())
fmt.Printf("release.chart: %s\n", rel.GetChart())
}
fmt.Printf("release.info: %s\n", rel.GetInfo())
fmt.Printf("release.chart: %s\n", rel.GetChart())
}
}
......
package main
import (
"fmt"
"sort"
"time"
"github.com/gosuri/uitable"
"github.com/kubernetes/helm/pkg/helm"
"github.com/kubernetes/helm/pkg/proto/hapi/release"
"github.com/kubernetes/helm/pkg/timeconv"
"github.com/spf13/cobra"
)
var listHelp = `
This command lists all of the currently deployed releases.
By default, items are sorted alphabetically. Sorting is done client-side, so if
the number of releases is less than the setting in '--max', some values will
be omitted, and in no particular lexicographic order.
`
var listCommand = &cobra.Command{
Use: "list [flags]",
Short: "List releases",
Long: listHelp,
RunE: listCmd,
Aliases: []string{"ls"},
}
var listLong bool
var listMax int
var listOffset int
var listByDate bool
func init() {
listCommand.Flags().BoolVarP(&listLong, "long", "l", false, "output long listing format")
listCommand.Flags().BoolVarP(&listByDate, "date", "d", false, "sort by release date")
listCommand.Flags().IntVarP(&listMax, "max", "m", 256, "maximum number of releases to fetch")
listCommand.Flags().IntVarP(&listOffset, "offset", "o", 0, "offset from start value (zero-indexed)")
RootCommand.AddCommand(listCommand)
}
func listCmd(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
fmt.Println("TODO: Implement filter.")
}
res, err := helm.ListReleases(listMax, listOffset)
if err != nil {
return err
}
rels := res.Releases
if res.Count+res.Offset < res.Total {
fmt.Println("Not all values were fetched.")
}
if listByDate {
sort.Sort(byDate(rels))
} else {
sort.Sort(byName(rels))
}
// Purty output, ya'll
if listLong {
return formatList(rels)
}
for _, r := range rels {
fmt.Println(r.Name)
}
return nil
}
func formatList(rels []*release.Release) error {
table := uitable.New()
table.MaxColWidth = 30
table.AddRow("NAME", "UPDATED", "CHART")
for _, r := range rels {
c := fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version)
t := timeconv.Format(r.Info.LastDeployed, time.ANSIC)
table.AddRow(r.Name, t, c)
}
fmt.Println(table)
return nil
}
// byName implements the sort.Interface for []*release.Release.
type byName []*release.Release
func (r byName) Len() int {
return len(r)
}
func (r byName) Swap(p, q int) {
r[p], r[q] = r[q], r[p]
}
func (r byName) Less(i, j int) bool {
return r[i].Name < r[j].Name
}
type byDate []*release.Release
func (r byDate) Len() int { return len(r) }
func (r byDate) Swap(p, q int) {
r[p], r[q] = r[q], r[p]
}
func (r byDate) Less(p, q int) bool {
return r[p].Info.LastDeployed.Seconds < r[q].Info.LastDeployed.Seconds
}
......@@ -3,6 +3,7 @@ package main
import (
"bytes"
"errors"
"fmt"
"log"
"github.com/kubernetes/helm/cmd/tiller/environment"
......@@ -33,8 +34,43 @@ var (
errMissingRelease = errors.New("no release provided")
)
// ListDefaultLimit is the default limit for number of items returned in a list.
var ListDefaultLimit int64 = 512
func (s *releaseServer) ListReleases(req *services.ListReleasesRequest, stream services.ReleaseService_ListReleasesServer) error {
return errNotImplemented
rels, err := s.env.Releases.List()
if err != nil {
return err
}
total := int64(len(rels))
l := int64(len(rels))
if req.Offset > 0 {
if req.Offset >= l {
return fmt.Errorf("offset %d is outside of range %d", req.Offset, l)
}
rels = rels[req.Offset:]
l = int64(len(rels))
}
if req.Limit == 0 {
req.Limit = ListDefaultLimit
}
if l > req.Limit {
rels = rels[0:req.Limit]
l = int64(len(rels))
}
res := &services.ListReleasesResponse{
Offset: 0,
Count: l,
Total: total,
Releases: rels,
}
stream.Send(res)
return nil
}
func (s *releaseServer) GetReleaseStatus(c ctx.Context, req *services.GetReleaseStatusRequest) (*services.GetReleaseStatusResponse, error) {
......
package main
import (
"fmt"
"strings"
"testing"
......@@ -12,6 +13,7 @@ import (
"github.com/kubernetes/helm/pkg/storage"
"github.com/kubernetes/helm/pkg/timeconv"
"golang.org/x/net/context"
"google.golang.org/grpc/metadata"
)
func rsFixture() *releaseServer {
......@@ -193,8 +195,44 @@ func TestGetReleaseStatus(t *testing.T) {
}
}
func TestListReleases(t *testing.T) {
rs := rsFixture()
num := 7
for i := 0; i < num; i++ {
rel := releaseMock()
rel.Name = fmt.Sprintf("rel-%d", i)
if err := rs.env.Releases.Create(rel); err != nil {
t.Fatalf("Could not store mock release: %s", err)
}
}
mrs := &mockListServer{}
if err := rs.ListReleases(&services.ListReleasesRequest{Offset: 0, Limit: 64}, mrs); err != nil {
t.Fatalf("Failed listing: %s", err)
}
if len(mrs.val.Releases) != num {
t.Errorf("Expected %d releases, got %d", num, len(mrs.val.Releases))
}
}
func mockEnvironment() *environment.Environment {
e := environment.New()
e.Releases = storage.NewMemory()
return e
}
type mockListServer struct {
val *services.ListReleasesResponse
}
func (l *mockListServer) Send(res *services.ListReleasesResponse) error {
l.val = res
return nil
}
func (l *mockListServer) Context() context.Context { return context.TODO() }
func (l *mockListServer) SendMsg(v interface{}) error { return nil }
func (l *mockListServer) RecvMsg(v interface{}) error { return nil }
func (l *mockListServer) SendHeader(m metadata.MD) error { return nil }
func (l *mockListServer) SetTrailer(m metadata.MD) {}
name: alpine
description: Deploy a basic Alpine Linux pod
version: 0.1.0
home: "https://github.com/kubernetes/helm"
home: https://github.com/kubernetes/helm
......@@ -13,8 +13,23 @@ var Config = &config{
}
// ListReleases lists the current releases.
func ListReleases(limit, offset int) (<-chan *services.ListReleasesResponse, error) {
return nil, ErrNotImplemented
func ListReleases(limit, offset int) (*services.ListReleasesResponse, error) {
c := Config.client()
if err := c.dial(); err != nil {
return nil, err
}
defer c.Close()
req := &services.ListReleasesRequest{
Limit: int64(limit),
Offset: int64(offset),
}
cli, err := c.impl.ListReleases(context.TODO(), req, c.cfg.CallOpts()...)
if err != nil {
return nil, err
}
return cli.Recv()
}
// GetReleaseStatus returns the given release's status.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment