Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions hack/test-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ echo "routes: ok"
osc get deploymentConfigs
osc get dc
osc create -f test/integration/fixtures/test-deployment-config.json
osc describe deploymentConfigs test-deployment-config
osc delete deploymentConfigs test-deployment-config
echo "deploymentConfigs: ok"

Expand Down
6 changes: 5 additions & 1 deletion pkg/cmd/cli/cmd/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ func NewFactory(clientConfig clientcmd.ClientConfig) *Factory {
if err != nil {
return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
}
describer, ok := describe.DescriberFor(mapping.Kind, cli, "")
kubeClient, err := kclient.New(cfg)
if err != nil {
return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
}
describer, ok := describe.DescriberFor(mapping.Kind, cli, kubeClient, "")
if !ok {
return nil, fmt.Errorf("no description has been implemented for %q", mapping.Kind)
}
Expand Down
117 changes: 101 additions & 16 deletions pkg/cmd/cli/describe/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import (
"text/tabwriter"

kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
labels "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"

"github.com/openshift/origin/pkg/client"
deployapi "github.com/openshift/origin/pkg/deploy/api"
deployutil "github.com/openshift/origin/pkg/deploy/util"
)

// DeploymentConfigDescriber generates information about a DeploymentConfig
Expand All @@ -19,39 +23,63 @@ type DeploymentConfigDescriber struct {
}

type deploymentDescriberClient interface {
GetDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error)
getDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error)
getDeployment(namespace, name string) (*kapi.ReplicationController, error)
listPods(namespace string, selector labels.Selector) (*kapi.PodList, error)
}

type genericDeploymentDescriberClient struct {
getDeploymentConfig func(namespace, name string) (*deployapi.DeploymentConfig, error)
getDeploymentConfigFunc func(namespace, name string) (*deployapi.DeploymentConfig, error)
getDeploymentFunc func(namespace, name string) (*kapi.ReplicationController, error)
listPodsFunc func(namespace string, selector labels.Selector) (*kapi.PodList, error)
}

func (c *genericDeploymentDescriberClient) GetDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error) {
return c.getDeploymentConfig(namespace, name)
func (c *genericDeploymentDescriberClient) getDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error) {
return c.getDeploymentConfigFunc(namespace, name)
}

func (c *genericDeploymentDescriberClient) getDeployment(namespace, name string) (*kapi.ReplicationController, error) {
return c.getDeploymentFunc(namespace, name)
}

func (c *genericDeploymentDescriberClient) listPods(namespace string, selector labels.Selector) (*kapi.PodList, error) {
return c.listPodsFunc(namespace, selector)
}

func NewDeploymentConfigDescriberForConfig(config *deployapi.DeploymentConfig) *DeploymentConfigDescriber {
return &DeploymentConfigDescriber{
client: &genericDeploymentDescriberClient{
getDeploymentConfig: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
return config, nil
},
getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
return nil, kerrors.NewNotFound("ReplicatonController", name)
},
listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
return nil, kerrors.NewNotFound("PodList", fmt.Sprintf("%v", selector))
},
},
}
}

func NewDeploymentConfigDescriber(client client.Interface) *DeploymentConfigDescriber {
func NewDeploymentConfigDescriber(client client.Interface, kclient kclient.Interface) *DeploymentConfigDescriber {
return &DeploymentConfigDescriber{
client: &genericDeploymentDescriberClient{
getDeploymentConfig: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
return client.DeploymentConfigs(namespace).Get(name)
},
getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
return kclient.ReplicationControllers(namespace).Get(name)
},
listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
return kclient.Pods(namespace).List(selector)
},
},
}
}

func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, error) {
deploymentConfig, err := d.client.GetDeploymentConfig(namespace, name)
deploymentConfig, err := d.client.getDeploymentConfig(namespace, name)
if err != nil {
return "", err
}
Expand All @@ -67,7 +95,19 @@ func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, er

printStrategy(deploymentConfig.Template.Strategy, out)
printTriggers(deploymentConfig.Triggers, out)
printReplicationController(deploymentConfig.Template.ControllerTemplate, out)
printReplicationControllerSpec(deploymentConfig.Template.ControllerTemplate, out)

deploymentName := deployutil.LatestDeploymentNameForConfig(deploymentConfig)
deployment, err := d.client.getDeployment(namespace, deploymentName)
if err != nil {
if kerrors.IsNotFound(err) {
formatString(out, "Latest Deployment", "<none>")
} else {
formatString(out, "Latest Deployment", fmt.Sprintf("error: %v", err))
}
} else {
printDeploymentRc(deployment, d.client, out)
}

return nil
})
Expand All @@ -92,7 +132,7 @@ func printStrategy(strategy deployapi.DeploymentStrategy, w io.Writer) {

func printTriggers(triggers []deployapi.DeploymentTriggerPolicy, w io.Writer) {
if len(triggers) == 0 {
fmt.Fprint(w, "No triggers.")
fmt.Fprint(w, "Triggers:\t<none>\n")
return
}

Expand All @@ -103,18 +143,26 @@ func printTriggers(triggers []deployapi.DeploymentTriggerPolicy, w io.Writer) {
case deployapi.DeploymentTriggerOnConfigChange:
fmt.Fprintf(w, "\t\t<no options>\n")
case deployapi.DeploymentTriggerOnImageChange:
fmt.Fprintf(w, "\t\tAutomatic:\t%v\n\t\tRepository:\t%s\n\t\tTag:\t%s\n",
t.ImageChangeParams.Automatic,
t.ImageChangeParams.RepositoryName,
t.ImageChangeParams.Tag,
)
if len(t.ImageChangeParams.RepositoryName) > 0 {
fmt.Fprintf(w, "\t\tAutomatic:\t%v\n\t\tRepository:\t%s\n\t\tTag:\t%s\n",
t.ImageChangeParams.Automatic,
t.ImageChangeParams.RepositoryName,
t.ImageChangeParams.Tag,
)
} else if len(t.ImageChangeParams.From.Name) > 0 {
fmt.Fprintf(w, "\t\tAutomatic:\t%v\n\t\tImage Repository:\t%s\n\t\tTag:\t%s\n",
t.ImageChangeParams.Automatic,
t.ImageChangeParams.From.Name,
t.ImageChangeParams.Tag,
)
}
default:
fmt.Fprint(w, "unknown\n")
}
}
}

func printReplicationController(spec kapi.ReplicationControllerSpec, w io.Writer) error {
func printReplicationControllerSpec(spec kapi.ReplicationControllerSpec, w io.Writer) error {
fmt.Fprint(w, "Template:\n")

fmt.Fprintf(w, "\tSelector:\t%s\n\tReplicas:\t%d\n",
Expand All @@ -131,6 +179,43 @@ func printReplicationController(spec kapi.ReplicationControllerSpec, w io.Writer
return nil
}

func printDeploymentRc(deployment *kapi.ReplicationController, client deploymentDescriberClient, w io.Writer) error {
running, waiting, succeeded, failed, err := getPodStatusForDeployment(deployment, client)
if err != nil {
return err
}

fmt.Fprint(w, "Latest Deployment:\n")
fmt.Fprintf(w, "\tName:\t%s\n", deployment.Name)
fmt.Fprintf(w, "\tStatus:\t%s\n", deployment.Annotations[deployapi.DeploymentStatusAnnotation])
fmt.Fprintf(w, "\tSelector:\t%s\n", formatLabels(deployment.Spec.Selector))
fmt.Fprintf(w, "\tLabels:\t%s\n", formatLabels(deployment.Labels))
fmt.Fprintf(w, "\tReplicas:\t%d current / %d desired\n", deployment.Status.Replicas, deployment.Spec.Replicas)
fmt.Fprintf(w, "\tPods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)

return nil
}

func getPodStatusForDeployment(deployment *kapi.ReplicationController, client deploymentDescriberClient) (running, waiting, succeeded, failed int, err error) {
rcPods, err := client.listPods(deployment.Namespace, labels.SelectorFromSet(deployment.Spec.Selector))
if err != nil {
return
}
for _, pod := range rcPods.Items {
switch pod.Status.Phase {
case kapi.PodRunning:
running++
case kapi.PodPending:
waiting++
case kapi.PodSucceeded:
succeeded++
case kapi.PodFailed:
failed++
}
}
return
}

// DeploymentDescriber generates information about a deployment
// DEPRECATED.
type DeploymentDescriber struct {
Expand Down
5 changes: 3 additions & 2 deletions pkg/cmd/cli/describe/describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import (
"strings"
"text/tabwriter"

kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
kctl "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
kruntime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"

buildapi "github.com/openshift/origin/pkg/build/api"
"github.com/openshift/origin/pkg/client"
)

func DescriberFor(kind string, c *client.Client, host string) (kctl.Describer, bool) {
func DescriberFor(kind string, c *client.Client, kclient kclient.Interface, host string) (kctl.Describer, bool) {
switch kind {
case "Build":
return &BuildDescriber{c}, true
Expand All @@ -22,7 +23,7 @@ func DescriberFor(kind string, c *client.Client, host string) (kctl.Describer, b
case "Deployment":
return &DeploymentDescriber{c}, true
case "DeploymentConfig":
return NewDeploymentConfigDescriber(c), true
return NewDeploymentConfigDescriber(c, kclient), true
case "Image":
return &ImageDescriber{c}, true
case "ImageRepository":
Expand Down
47 changes: 44 additions & 3 deletions pkg/cmd/cli/describe/describer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import (
"strings"
"testing"

kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/openshift/origin/pkg/client"

deployapi "github.com/openshift/origin/pkg/deploy/api"
deployapitest "github.com/openshift/origin/pkg/deploy/api/test"
deployutil "github.com/openshift/origin/pkg/deploy/util"
)

type describeClient struct {
Expand All @@ -24,7 +29,7 @@ func TestDescribeFor(t *testing.T) {
"Image", "ImageRepository", "Route", "Project",
}
for _, o := range testTypesList {
_, ok := DescriberFor(o, c, "")
_, ok := DescriberFor(o, c, &kclient.Fake{}, "")
if !ok {
t.Errorf("Unable to obtain describer for %s", o)
}
Expand Down Expand Up @@ -59,8 +64,23 @@ func TestDescribers(t *testing.T) {
}

func TestDeploymentConfigDescriber(t *testing.T) {
config := deployapitest.OkDeploymentConfig(0)
d := NewDeploymentConfigDescriberForConfig(config)
config := deployapitest.OkDeploymentConfig(1)
deployment, _ := deployutil.MakeDeployment(config, kapi.Codec)
podList := &kapi.PodList{}

d := &DeploymentConfigDescriber{
client: &genericDeploymentDescriberClient{
getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
return config, nil
},
getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
return deployment, nil
},
listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
return podList, nil
},
},
}

describe := func() {
if output, err := d.Describe("test", "deployment"); err != nil {
Expand All @@ -70,11 +90,32 @@ func TestDeploymentConfigDescriber(t *testing.T) {
}
}

podList.Items = []kapi.Pod{*mkPod(kapi.PodRunning, 0)}
describe()

config.Triggers = append(config.Triggers, deployapitest.OkConfigChangeTrigger())
describe()

config.Template.Strategy = deployapitest.OkCustomStrategy()
describe()

config.Triggers[0].ImageChangeParams.RepositoryName = ""
config.Triggers[0].ImageChangeParams.From = kapi.ObjectReference{Name: "imageRepo"}
describe()
}

func mkPod(status kapi.PodPhase, exitCode int) *kapi.Pod {
return &kapi.Pod{
ObjectMeta: kapi.ObjectMeta{Name: "PodName"},
Status: kapi.PodStatus{
Phase: status,
Info: kapi.PodInfo{
"container1": kapi.ContainerStatus{
State: kapi.ContainerState{
Termination: &kapi.ContainerStateTerminated{ExitCode: exitCode},
},
},
},
},
}
}