Skip to content

Commit 1e29a56

Browse files
Merge pull request #18723 from juanvallejo/jvallejo/mark-found-deployment-nodes
Automatic merge from submit-queue. tags existing deployment nodes as "found" Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1544183#c3 Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1540560#c7 Followup to: #18579 cc @soltysh
2 parents a1c2561 + 6c7059f commit 1e29a56

File tree

7 files changed

+303
-2
lines changed

7 files changed

+303
-2
lines changed

pkg/oc/cli/describe/projectstatus.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func (d *ProjectStatusDescriber) MakeGraph(namespace string) (osgraph.Graph, set
9898
&horizontalPodAutoscalerLoader{namespace: namespace, lister: d.KubeClient.Autoscaling()},
9999
&deploymentLoader{namespace: namespace, lister: d.KubeClient.Extensions()},
100100
&replicasetLoader{namespace: namespace, lister: d.KubeClient.Extensions()},
101+
&daemonsetLoader{namespace: namespace, lister: d.KubeClient.Extensions()},
101102
// TODO check swagger for feature enablement and selectively add bcLoader and buildLoader
102103
// then remove errors.TolerateNotFoundError method.
103104
&bcLoader{namespace: namespace, lister: d.BuildClient},
@@ -203,6 +204,9 @@ func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error
203204
standaloneDeployments, coveredByDeployments := graphview.AllDeployments(g, coveredNodes)
204205
coveredNodes.Insert(coveredByDeployments.List()...)
205206

207+
standaloneStatefulSets, coveredByStatefulSets := graphview.AllStatefulSets(g, coveredNodes)
208+
coveredNodes.Insert(coveredByStatefulSets.List()...)
209+
206210
standaloneRCs, coveredByRCs := graphview.AllReplicationControllers(g, coveredNodes)
207211
coveredNodes.Insert(coveredByRCs.List()...)
208212

@@ -212,6 +216,9 @@ func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error
212216
standaloneImages, coveredByImages := graphview.AllImagePipelinesFromBuildConfig(g, coveredNodes)
213217
coveredNodes.Insert(coveredByImages.List()...)
214218

219+
standaloneDaemonSets, coveredByDaemonSets := graphview.AllDaemonSets(g, coveredNodes)
220+
coveredNodes.Insert(coveredByDaemonSets.List()...)
221+
215222
standalonePods, coveredByPods := graphview.AllPods(g, coveredNodes)
216223
coveredNodes.Insert(coveredByPods.List()...)
217224

@@ -318,6 +325,15 @@ func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error
318325
})...)
319326
}
320327

328+
for _, standaloneStatefulSet := range standaloneStatefulSets {
329+
if !standaloneStatefulSet.StatefulSet.Found() {
330+
continue
331+
}
332+
333+
fmt.Fprintln(out)
334+
printLines(out, indent, 0, describeStatefulSetInServiceGroup(f, standaloneStatefulSet)...)
335+
}
336+
321337
for _, standaloneImage := range standaloneImages {
322338
fmt.Fprintln(out)
323339
lines := describeStandaloneBuildGroup(f, standaloneImage, namespace)
@@ -343,6 +359,15 @@ func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error
343359
printLines(out, indent, 0, describeRSInServiceGroup(f, standaloneRS.RS)...)
344360
}
345361

362+
for _, standaloneDaemonSet := range standaloneDaemonSets {
363+
if !standaloneDaemonSet.DaemonSet.Found() {
364+
continue
365+
}
366+
367+
fmt.Fprintln(out)
368+
printLines(out, indent, 0, describeDaemonSetInServiceGroup(f, standaloneDaemonSet)...)
369+
}
370+
346371
monopods, err := filterBoringPods(standalonePods)
347372
if err != nil {
348373
return err
@@ -586,6 +611,9 @@ func (f namespacedFormatter) ResourceName(obj interface{}) string {
586611
case *kubegraph.PersistentVolumeClaimNode:
587612
return namespaceNameWithType("pvc", t.PersistentVolumeClaim.Name, t.PersistentVolumeClaim.Namespace, f.currentNamespace, f.hideNamespace)
588613

614+
case *kubegraph.DaemonSetNode:
615+
return namespaceNameWithType("daemonset", t.DaemonSet.Name, t.DaemonSet.Namespace, f.currentNamespace, f.hideNamespace)
616+
589617
case *imagegraph.ImageStreamNode:
590618
return namespaceNameWithType("is", t.ImageStream.Name, t.ImageStream.Namespace, f.currentNamespace, f.hideNamespace)
591619
case *imagegraph.ImageStreamTagNode:
@@ -723,6 +751,42 @@ func describeStatefulSetInServiceGroup(f formatter, node graphview.StatefulSet)
723751
return lines
724752
}
725753

754+
func describeDaemonSetInServiceGroup(f formatter, node graphview.DaemonSet) []string {
755+
local := namespacedFormatter{currentNamespace: node.DaemonSet.DaemonSet.Namespace}
756+
includeLastPass := false
757+
758+
if len(node.Images) == 1 {
759+
format := "%s manages %s %s"
760+
lines := []string{fmt.Sprintf(format, f.ResourceName(node.DaemonSet), describeImageInPipeline(local, node.Images[0], node.DaemonSet.DaemonSet.Namespace), "")}
761+
if len(lines[0]) > 120 && strings.Contains(lines[0], " <- ") {
762+
segments := strings.SplitN(lines[0], " <- ", 2)
763+
lines[0] = segments[0] + " <-"
764+
lines = append(lines, segments[1])
765+
}
766+
767+
lines = append(lines, indentLines(" ", describeAdditionalBuildDetail(node.Images[0].Build, node.Images[0].LastSuccessfulBuild, node.Images[0].LastUnsuccessfulBuild, node.Images[0].ActiveBuilds, node.Images[0].DestinationResolved, includeLastPass)...)...)
768+
lines = append(lines, describeDaemonSetStatus(node.DaemonSet.DaemonSet))
769+
return lines
770+
}
771+
772+
images := []string{}
773+
for _, container := range node.DaemonSet.DaemonSet.Spec.Template.Spec.Containers {
774+
images = append(images, container.Image)
775+
}
776+
imagesWithoutTriggers := ""
777+
if len(node.Images) == 0 {
778+
imagesWithoutTriggers = strings.Join(images, ",")
779+
}
780+
format := "%s manages %s"
781+
lines := []string{fmt.Sprintf(format, f.ResourceName(node.DaemonSet), imagesWithoutTriggers)}
782+
for _, image := range node.Images {
783+
lines = append(lines, describeImageInPipeline(local, image, node.DaemonSet.DaemonSet.Namespace))
784+
lines = append(lines, indentLines(" ", describeAdditionalBuildDetail(image.Build, image.LastSuccessfulBuild, image.LastUnsuccessfulBuild, image.ActiveBuilds, image.DestinationResolved, includeLastPass)...)...)
785+
}
786+
lines = append(lines, describeDaemonSetStatus(node.DaemonSet.DaemonSet))
787+
return lines
788+
}
789+
726790
func describeRCInServiceGroup(f formatter, rcNode *kubegraph.ReplicationControllerNode) []string {
727791
if rcNode.ReplicationController.Spec.Template == nil {
728792
return []string{}
@@ -1282,6 +1346,12 @@ func describeStatefulSetStatus(p *kapps.StatefulSet) string {
12821346
return fmt.Sprintf("created %s ago%s", timeAt, describePodSummaryInline(int32(p.Status.Replicas), int32(p.Status.Replicas), int32(p.Spec.Replicas), false, 0))
12831347
}
12841348

1349+
func describeDaemonSetStatus(ds *kapisext.DaemonSet) string {
1350+
timeAt := strings.ToLower(formatRelativeTime(ds.CreationTimestamp.Time))
1351+
replicaSetRevision := ds.Generation
1352+
return fmt.Sprintf("generation #%d running for %s%s", replicaSetRevision, timeAt, describePodSummaryInline(ds.Status.NumberReady, ds.Status.NumberAvailable, ds.Status.DesiredNumberScheduled, false, 0))
1353+
}
1354+
12851355
func describeRCStatus(rc *kapi.ReplicationController) string {
12861356
timeAt := strings.ToLower(formatRelativeTime(rc.CreationTimestamp.Time))
12871357
return fmt.Sprintf("rc/%s created %s ago%s", rc.Name, timeAt, describePodSummaryInline(rc.Status.ReadyReplicas, rc.Status.Replicas, rc.Spec.Replicas, false, 0))
@@ -1590,6 +1660,30 @@ func (l *deploymentLoader) AddToGraph(g osgraph.Graph) error {
15901660
return nil
15911661
}
15921662

1663+
type daemonsetLoader struct {
1664+
namespace string
1665+
lister kapisextclient.DaemonSetsGetter
1666+
items []kapisext.DaemonSet
1667+
}
1668+
1669+
func (l *daemonsetLoader) Load() error {
1670+
list, err := l.lister.DaemonSets(l.namespace).List(metav1.ListOptions{})
1671+
if err != nil {
1672+
return err
1673+
}
1674+
1675+
l.items = list.Items
1676+
return nil
1677+
}
1678+
1679+
func (l *daemonsetLoader) AddToGraph(g osgraph.Graph) error {
1680+
for i := range l.items {
1681+
kubegraph.EnsureDaemonSetNode(g, &l.items[i])
1682+
}
1683+
1684+
return nil
1685+
}
1686+
15931687
type replicasetLoader struct {
15941688
namespace string
15951689
lister kapisextclient.ReplicaSetsGetter

pkg/oc/cli/describe/projectstatus_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,32 @@ func TestProjectStatus(t *testing.T) {
433433
},
434434
Time: mustParseTime("2016-04-07T04:12:25Z"),
435435
},
436+
"standalone daemonset": {
437+
File: "rollingupdate-daemonset.yaml",
438+
Extra: []runtime.Object{
439+
&projectapi.Project{
440+
ObjectMeta: metav1.ObjectMeta{Name: "example", Namespace: ""},
441+
},
442+
},
443+
ErrFn: func(err error) bool { return err == nil },
444+
Contains: []string{
445+
"daemonset/bind manages gcr.io/google-containers/pause:2.0",
446+
"generation #0 running for about a minute",
447+
},
448+
Time: mustParseTime("2016-04-07T04:12:25Z"),
449+
},
450+
"hpa non-missing scaleref": {
451+
File: "hpa-with-scale-ref.yaml",
452+
Extra: []runtime.Object{
453+
&projectapi.Project{
454+
ObjectMeta: metav1.ObjectMeta{Name: "example", Namespace: ""},
455+
},
456+
},
457+
ErrFn: func(err error) bool { return err == nil },
458+
Contains: []string{
459+
"deployment/ruby-deploy deploys istag/ruby-deploy:latest",
460+
},
461+
},
436462
}
437463
oldTimeFn := timeNowFn
438464
defer func() { timeNowFn = oldTimeFn }()
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package graphview
2+
3+
import (
4+
appsedges "github.com/openshift/origin/pkg/oc/graph/appsgraph"
5+
osgraph "github.com/openshift/origin/pkg/oc/graph/genericgraph"
6+
kubeedges "github.com/openshift/origin/pkg/oc/graph/kubegraph"
7+
kubegraph "github.com/openshift/origin/pkg/oc/graph/kubegraph/nodes"
8+
)
9+
10+
type DaemonSet struct {
11+
DaemonSet *kubegraph.DaemonSetNode
12+
13+
OwnedPods []*kubegraph.PodNode
14+
CreatedPods []*kubegraph.PodNode
15+
16+
Images []ImagePipeline
17+
}
18+
19+
// AllDaemonSets returns all the DaemonSets that aren't in the excludes set and the set of covered NodeIDs
20+
func AllDaemonSets(g osgraph.Graph, excludeNodeIDs IntSet) ([]DaemonSet, IntSet) {
21+
covered := IntSet{}
22+
views := []DaemonSet{}
23+
24+
for _, uncastNode := range g.NodesByKind(kubegraph.DaemonSetNodeKind) {
25+
if excludeNodeIDs.Has(uncastNode.ID()) {
26+
continue
27+
}
28+
29+
view, covers := NewDaemonSet(g, uncastNode.(*kubegraph.DaemonSetNode))
30+
covered.Insert(covers.List()...)
31+
views = append(views, view)
32+
}
33+
34+
return views, covered
35+
}
36+
37+
// NewDaemonSet returns the DaemonSet and a set of all the NodeIDs covered by the DaemonSet
38+
func NewDaemonSet(g osgraph.Graph, node *kubegraph.DaemonSetNode) (DaemonSet, IntSet) {
39+
covered := IntSet{}
40+
covered.Insert(node.ID())
41+
42+
view := DaemonSet{}
43+
view.DaemonSet = node
44+
45+
for _, uncastPodNode := range g.PredecessorNodesByEdgeKind(node, kubeedges.ManagedByControllerEdgeKind) {
46+
podNode := uncastPodNode.(*kubegraph.PodNode)
47+
covered.Insert(podNode.ID())
48+
view.OwnedPods = append(view.OwnedPods, podNode)
49+
}
50+
51+
for _, istNode := range g.PredecessorNodesByEdgeKind(node, kubeedges.TriggersDeploymentEdgeKind) {
52+
imagePipeline, covers := NewImagePipelineFromImageTagLocation(g, istNode, istNode.(ImageTagLocation))
53+
covered.Insert(covers.List()...)
54+
view.Images = append(view.Images, imagePipeline)
55+
}
56+
57+
// for image that we use, create an image pipeline and add it to the list
58+
for _, tagNode := range g.PredecessorNodesByEdgeKind(node, appsedges.UsedInDeploymentEdgeKind) {
59+
imagePipeline, covers := NewImagePipelineFromImageTagLocation(g, tagNode, tagNode.(ImageTagLocation))
60+
61+
covered.Insert(covers.List()...)
62+
view.Images = append(view.Images, imagePipeline)
63+
}
64+
65+
return view, covered
66+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
apiVersion: v1
2+
items:
3+
- apiVersion: extensions/v1beta1
4+
kind: Deployment
5+
metadata:
6+
annotations:
7+
deployment.kubernetes.io/revision: "1"
8+
image.openshift.io/triggers: '[{"from":{"kind":"ImageStreamTag","name":"ruby-deploy:latest"},"fieldPath":"spec.template.spec.containers[?(@.name==\"ruby-deploy\")].image"}]'
9+
openshift.io/generated-by: OpenShiftNewApp
10+
generation: 1
11+
labels:
12+
app: ruby-deploy
13+
name: ruby-deploy
14+
spec:
15+
progressDeadlineSeconds: 600
16+
replicas: 1
17+
revisionHistoryLimit: 10
18+
selector:
19+
matchLabels:
20+
app: ruby-deploy
21+
strategy:
22+
rollingUpdate:
23+
maxSurge: 25%
24+
maxUnavailable: 25%
25+
type: RollingUpdate
26+
template:
27+
metadata:
28+
creationTimestamp: null
29+
labels:
30+
app: ruby-deploy
31+
spec:
32+
containers:
33+
- image: busybox@sha256:4cee1979ba0bf7db9fc5d28fb7b798ca69ae95a47c5fecf46327720df4ff352d
34+
imagePullPolicy: IfNotPresent
35+
name: ruby-deploy
36+
ports:
37+
- containerPort: 8080
38+
protocol: TCP
39+
resources: {}
40+
terminationMessagePath: /dev/termination-log
41+
terminationMessagePolicy: File
42+
dnsPolicy: ClusterFirst
43+
restartPolicy: Always
44+
schedulerName: default-scheduler
45+
securityContext: {}
46+
terminationGracePeriodSeconds: 30
47+
status:
48+
conditions:
49+
- lastTransitionTime: 2018-02-24T00:51:47Z
50+
lastUpdateTime: 2018-02-24T00:51:47Z
51+
message: Deployment does not have minimum availability.
52+
reason: MinimumReplicasUnavailable
53+
status: "False"
54+
type: Available
55+
- lastTransitionTime: 2018-02-24T00:51:47Z
56+
lastUpdateTime: 2018-02-24T00:51:47Z
57+
message: ReplicaSet "ruby-deploy-599994c49b" is progressing.
58+
reason: ReplicaSetUpdated
59+
status: "True"
60+
type: Progressing
61+
observedGeneration: 1
62+
replicas: 1
63+
unavailableReplicas: 1
64+
updatedReplicas: 1
65+
- apiVersion: autoscaling/v1
66+
kind: HorizontalPodAutoscaler
67+
metadata:
68+
name: ruby-deploy
69+
spec:
70+
maxReplicas: 1
71+
minReplicas: 1
72+
scaleTargetRef:
73+
apiVersion: extensions/v1beta1
74+
kind: Deployment
75+
name: ruby-deploy
76+
targetCPUUtilizationPercentage: 80
77+
status:
78+
currentReplicas: 0
79+
desiredReplicas: 0
80+
kind: List
81+
metadata:
82+
resourceVersion: ""
83+
selfLink: ""
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
apiVersion: extensions/v1beta1
2+
kind: DaemonSet
3+
metadata:
4+
name: bind
5+
creationTimestamp: 2016-04-07T04:11:25Z
6+
spec:
7+
updateStrategy:
8+
type: RollingUpdate
9+
rollingUpdate:
10+
maxUnavailable: 10%
11+
template:
12+
metadata:
13+
labels:
14+
service: bind
15+
spec:
16+
affinity:
17+
podAntiAffinity:
18+
requiredDuringSchedulingIgnoredDuringExecution:
19+
- labelSelector:
20+
matchExpressions:
21+
- key: "service"
22+
operator: "In"
23+
values: ["bind"]
24+
topologyKey: "kubernetes.io/hostname"
25+
namespaces: []
26+
containers:
27+
- name: kubernetes-pause
28+
image: gcr.io/google-containers/pause:2.0

pkg/oc/graph/kubegraph/edges.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ func AddAllManagedByControllerPodEdges(g osgraph.MutableUniqueGraph) {
137137
case *kubegraph.StatefulSetNode:
138138
// TODO: refactor to handle expanded selectors (along with ReplicaSets and Deployments)
139139
AddManagedByControllerPodEdges(g, cast, cast.StatefulSet.Namespace, cast.StatefulSet.Spec.Selector.MatchLabels)
140+
case *kubegraph.DaemonSetNode:
141+
AddManagedByControllerPodEdges(g, cast, cast.DaemonSet.Namespace, cast.DaemonSet.Spec.Selector.MatchLabels)
140142
}
141143
}
142144
}
@@ -258,6 +260,8 @@ func AddHPAScaleRefEdges(g osgraph.Graph) {
258260
syntheticNode = appsgraph.FindOrCreateSyntheticDeploymentConfigNode(g, &appsapi.DeploymentConfig{ObjectMeta: syntheticMeta})
259261
case r == extensions.Resource("deployments"):
260262
syntheticNode = kubegraph.FindOrCreateSyntheticDeploymentNode(g, &extensions.Deployment{ObjectMeta: syntheticMeta})
263+
case r == extensions.Resource("replicasets"):
264+
syntheticNode = kubegraph.FindOrCreateSyntheticReplicaSetNode(g, &extensions.ReplicaSet{ObjectMeta: syntheticMeta})
261265
default:
262266
continue
263267
}

0 commit comments

Comments
 (0)