Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Add ListImages summary fields #1084

Merged
merged 7 commits into from
May 21, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions api/v6/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,19 @@ type ControllerStatus struct {
}

type Container struct {
Name string
Current image.Info
Available []image.Info
AvailableError string `json:",omitempty"`
Name string `json:",omitempty"`
Current image.Info `json:",omitempty"`
LatestFiltered image.Info `json:",omitempty"`

// All available images (ignoring tag filters)
Available []image.Info `json:",omitempty"`
AvailableError string `json:",omitempty"`
AvailableImagesCount int `json:",omitempty"`
NewAvailableImagesCount int `json:",omitempty"`

// Filtered available images (matching tag filters)
FilteredImagesCount int `json:",omitempty"`
NewFilteredImagesCount int `json:",omitempty"`
}

// --- config types
Expand All @@ -66,13 +75,17 @@ type Deprecated interface {
SyncNotify(context.Context) error
}

type ListImagesOptions struct {
OverrideContainerFields []string
}

type NotDeprecated interface {
// from v5
Export(context.Context) ([]byte, error)

// v6
ListServices(ctx context.Context, namespace string) ([]ControllerStatus, error)
ListImages(context.Context, update.ResourceSpec) ([]ImageStatus, error)
ListImages(ctx context.Context, spec update.ResourceSpec, opts ListImagesOptions) ([]ImageStatus, error)
UpdateManifests(context.Context, update.Spec) (job.ID, error)
SyncStatus(ctx context.Context, ref string) ([]string, error)
JobStatus(context.Context, job.ID) (job.Status, error)
Expand Down
2 changes: 1 addition & 1 deletion cmd/fluxctl/list_images_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (opts *controllerShowOpts) RunE(cmd *cobra.Command, args []string) error {

ctx := context.Background()

controllers, err := opts.API.ListImages(ctx, resourceSpec)
controllers, err := opts.API.ListImages(ctx, resourceSpec, v6.ListImagesOptions{})
if err != nil {
return err
}
Expand Down
148 changes: 118 additions & 30 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,35 +70,43 @@ func (d *Daemon) Export(ctx context.Context) ([]byte, error) {
return d.Cluster.Export()
}

func (d *Daemon) ListServices(ctx context.Context, namespace string) ([]v6.ControllerStatus, error) {
clusterServices, err := d.Cluster.AllControllers(namespace)
if err != nil {
return nil, errors.Wrap(err, "getting services from cluster")
}

func (d *Daemon) getPolicyResourceMap(ctx context.Context) (policy.ResourceMap, v6.ReadOnlyReason, error) {
var services policy.ResourceMap
var globalReadOnly v6.ReadOnlyReason
err = d.WithClone(ctx, func(checkout *git.Checkout) error {
err := d.WithClone(ctx, func(checkout *git.Checkout) error {
var err error
services, err = d.Manifests.ServicesWithPolicies(checkout.ManifestDir())
return err
})

// Capture errors related to read-only repositories
switch {
case err == git.ErrNotReady:
globalReadOnly = v6.ReadOnlyNotReady
case err == git.ErrNoConfig:
globalReadOnly = v6.ReadOnlyNoRepo
case err != nil:
return nil, errors.Wrap(err, "getting service policies")
return nil, globalReadOnly, errors.Wrap(err, "getting service policies")
}

return services, globalReadOnly, nil
}

func (d *Daemon) ListServices(ctx context.Context, namespace string) ([]v6.ControllerStatus, error) {
clusterServices, err := d.Cluster.AllControllers(namespace)
if err != nil {
return nil, errors.Wrap(err, "getting services from cluster")
}

policyResourceMap, readOnly, err := d.getPolicyResourceMap(ctx)
if err != nil {
return nil, err
}

var res []v6.ControllerStatus
for _, service := range clusterServices {
var readOnly v6.ReadOnlyReason
policies, ok := services[service.ID]
policies, ok := policyResourceMap[service.ID]
switch {
case globalReadOnly != "":
readOnly = globalReadOnly
case !ok:
readOnly = v6.ReadOnlyMissing
case service.IsSystem:
Expand Down Expand Up @@ -130,7 +138,7 @@ func (cs clusterContainers) Containers(i int) []resource.Container {
}

// List the images available for set of services
func (d *Daemon) ListImages(ctx context.Context, spec update.ResourceSpec) ([]v6.ImageStatus, error) {
func (d *Daemon) ListImages(ctx context.Context, spec update.ResourceSpec, opts v6.ListImagesOptions) ([]v6.ImageStatus, error) {
var services []cluster.Controller
var err error
if spec == update.ResourceSpecAll {
Expand All @@ -143,17 +151,25 @@ func (d *Daemon) ListImages(ctx context.Context, spec update.ResourceSpec) ([]v6
services, err = d.Cluster.SomeControllers([]flux.ResourceID{id})
}

images, err := update.CollectAvailableImages(d.Registry, clusterContainers(services), d.Logger)
imageRepos, err := update.FetchImageRepos(d.Registry, clusterContainers(services), d.Logger)
if err != nil {
return nil, errors.Wrap(err, "getting images for services")
}

policyResourceMap, _, err := d.getPolicyResourceMap(ctx)
if err != nil {
return nil, err
}

var res []v6.ImageStatus
for _, service := range services {
containers := containersWithAvailable(service, images)
serviceContainers, err := getServiceContainers(service, imageRepos, policyResourceMap, opts.OverrideContainerFields)
if err != nil {
return nil, err
}
res = append(res, v6.ImageStatus{
ID: service.ID,
Containers: containers,
Containers: serviceContainers,
})
}

Expand Down Expand Up @@ -544,23 +560,95 @@ func containers2containers(cs []resource.Container) []v6.Container {
return res
}

func containersWithAvailable(service cluster.Controller, images update.ImageMap) (res []v6.Container) {
func getServiceContainers(service cluster.Controller, imageRepos update.ImageRepos, policyResourceMap policy.ResourceMap, overrideFields []string) (res []v6.Container, err error) {
fields := map[string]struct{}{

This comment was marked as abuse.

"Name": struct{}{},
"Current": struct{}{},
"LatestFiltered": struct{}{},
"Available": struct{}{},
"AvailableError": struct{}{},
"AvailableImagesCount": struct{}{},
"NewAvailableImagesCount": struct{}{},
"FilteredImagesCount": struct{}{},
"NewFilteredImagesCount": struct{}{},
}

// If overrideFields is provided, override the default fields to return
if len(overrideFields) > 0 {
newFieldsMap := make(map[string]struct{})
for _, f := range overrideFields {
if _, ok := fields[f]; !ok {
return nil, errors.Errorf("%s is an invalid field", f)
}
newFieldsMap[f] = struct{}{}
}
fields = newFieldsMap
}

for _, c := range service.ContainersOrNil() {
available := images.Available(c.Image.Name)
availableErr := ""
if available == nil {
availableErr = registry.ErrNoImageData.Error()
var container v6.Container

imageRepo := c.Image.Name
tagPattern := getTagPattern(policyResourceMap, service.ID, c.Name)
currentImage := imageRepos.FindImageInfo(imageRepo, c.Image)

// All available images
availableImages := imageRepos.Available(imageRepo)
availableImagesCount := len(availableImages)
availableImagesErr := ""
if availableImages == nil {
availableImagesErr = registry.ErrNoImageData.Error()
}
res = append(res, v6.Container{
Name: c.Name,
Current: image.Info{
ID: c.Image,
},
Available: available,
AvailableError: availableErr,
})
var newAvailableImages []image.Info
for _, img := range availableImages {
if img.CreatedAt.After(currentImage.CreatedAt) {
newAvailableImages = append(newAvailableImages, img)
}
}
newAvailableImagesCount := len(newAvailableImages)

// Filtered available images
filteredImages := imageRepos.FilteredAvailable(imageRepo, tagPattern)
filteredImagesCount := len(filteredImages)
var newFilteredImages []image.Info
for _, img := range filteredImages {
if img.CreatedAt.After(currentImage.CreatedAt) {
newFilteredImages = append(newFilteredImages, img)
}
}
newFilteredImagesCount := len(newFilteredImages)

if _, ok := fields["Name"]; ok {

This comment was marked as abuse.

container.Name = c.Name
}
if _, ok := fields["Current"]; ok {
container.Current = currentImage
}
if _, ok := fields["LatestFiltered"]; ok {
container.LatestFiltered, _ = imageRepos.LatestFilteredImage(imageRepo, tagPattern)
}
if _, ok := fields["Available"]; ok {
container.Available = availableImages
}
if _, ok := fields["AvailableError"]; ok {
container.AvailableError = availableImagesErr
}
if _, ok := fields["AvailableImagesCount"]; ok {
container.AvailableImagesCount = availableImagesCount
}
if _, ok := fields["NewAvailableImagesCount"]; ok {
container.NewAvailableImagesCount = newAvailableImagesCount
}
if _, ok := fields["FilteredImagesCount"]; ok {
container.FilteredImagesCount = filteredImagesCount
}
if _, ok := fields["NewFilteredImagesCount"]; ok {
container.NewFilteredImagesCount = newFilteredImagesCount
}
res = append(res, container)
}
return res

return res, nil
}

func policyCommitMessage(us policy.Updates, cause update.Cause) string {
Expand Down
Loading