Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route creation with oc new-app #16396

Merged
merged 1 commit into from
Sep 22, 2017

Conversation

mjudeikis
Copy link
Contributor

Story: https://trello.com/c/Ve6T2QUL/1336-create-routes-from-oc-new-app-appcreation

Comments more than welcome as I'm not familiar with the codebase.

@openshift-ci-robot openshift-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Sep 16, 2017
@bparees
Copy link
Contributor

bparees commented Sep 18, 2017

/unassign @smarterclayton
/unassign @juanvallejo
/assign
/assign @jim-minter

Copy link
Contributor

@jim-minter jim-minter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great start @mangirdaz!

@@ -133,6 +134,15 @@ func checkStatefulSetReadiness(oc client.Interface, obj runtime.Object) (bool, b
return ready, failed, nil
}

// checkRouteReadiness checks if host fiels was prepoplated already.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/fiels/field/
s/prepoplated/prepopulated/

@@ -133,6 +134,15 @@ func checkStatefulSetReadiness(oc client.Interface, obj runtime.Object) (bool, b
return ready, failed, nil
}

// checkRouteReadiness checks if host fiels was prepoplated already.
func checkRouteReadiness(oc client.Interface, obj runtime.Object) (bool, bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add two tests to TestCheckReadiness in pkg/template/controller/readiness_test.go, showing a Route that will return !ready, and one that will return ready

@@ -146,6 +156,7 @@ var readinessCheckers = map[schema.GroupKind]func(client.Interface, runtime.Obje
deployapi.Kind("DeploymentConfig"): checkDeploymentConfigReadiness,
batch.Kind("Job"): checkJobReadiness,
apps.Kind("StatefulSet"): checkStatefulSetReadiness,
routeapi.Kind("Route"): checkRouteReadiness,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need an additional line routeapi.LegacyKind("Route"): checkRouteReadiness, here. This will handle objects with apiVersion: v1, kind: Route. Your existing line only handles objects with apiVersion: route.openshift.io/v1, kind: Route.

@@ -373,6 +374,10 @@ func (o *NewAppOptions) RunNewApp() error {
hasMissingRepo = true
fmt.Fprintf(out, "%sWARNING: No Docker registry has been configured with the server. Automatic builds and deployments may not function.\n", indent)
}
case *routeapi.Route:
if len(t.Spec.Host) > 0 {
fmt.Fprintf(out, "%sThe Access application via route '%s' \n", indent, t.Spec.Host)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/The Access application/Access your app/

fmt.Fprintf(out, "%sRun '%s %s' to view your app.\n", indent, o.BaseName, StatusRecommendedName)
}
return nil
}

type LogsForObjectFunc func(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error)

func containsRoute(item []runtime.Object) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd remove this function and just set a flag variable if you find a Route when iterating result.List.Items in RunNewApp()

return false
}

func getAllServices(item []runtime.Object) []string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func getServices(items []runtime.Object) []*kapi.Service would be a better signature

@@ -385,13 +390,45 @@ func (o *NewAppOptions) RunNewApp() error {
fmt.Fprintf(out, "%sTrack installation of %s with '%s logs %s'.\n", indent, installing[i].Name, o.BaseName, installing[i].Name)
}
case len(result.List.Items) > 0:
//if we dont find a route we give a message to expose it
if !containsRoute(result.List.Items) {
//we if dont have any route but have services - suggest commndas to expose those
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spelling

//we if dont have any route but have services - suggest commndas to expose those
svc := getAllServices(result.List.Items)
if len(svc) > 0 {
fmt.Fprintf(out, "%sApplication is not exposed. You can expose it to outside world by executing one or all of the commands below \n", indent)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure on the final wording for this: maybe the following is better?
"%sApp is not exposed. You can expose services to the outside world by executing one or more of the commands below:\n"

@jim-minter
Copy link
Contributor

@mangirdaz also, can you see if you can get a couple of new tests together in test/cmd/newapp.sh ? For example something like os::cmd::expect_success_and_text 'oc new-app mysql --dry-run' 'Application is not exposed'

@mjudeikis
Copy link
Contributor Author

mjudeikis commented Sep 20, 2017

@jim-minter fixed as per comments.

  • will add tests for new app sh script for testing. Was wondering how you test this :)

@mjudeikis
Copy link
Contributor Author

/test cmd

for _, i := range result.List.Items {
switch i.(type) {
case *routeapi.Route:
containRoute = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to push this up to around line 377 to save the additional iteration - is that possible?

func getServices(items []runtime.Object) []*kapi.Service {
var svc []*kapi.Service
for _, i := range items {
switch i.(type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to change it, but for reference, you can also do if s, ok := i.(*kapi.Service); ok { svc = append(svc, s) }

@@ -36,6 +36,8 @@ os::cmd::expect_success_and_text 'oc new-app mysql --dry-run' 'tag "5.7" for "my
# test deployments are created with the boolean flag and printed in the UI
os::cmd::expect_success_and_text 'oc new-app mysql --dry-run --as-test' 'This image will be test deployed'
os::cmd::expect_success_and_text 'oc new-app mysql -o yaml --as-test' 'test: true'
os::cmd::expect_success_and_text 'oc new-app mysql --as-test' 'Application is not exposed'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if you add --dry-run here, it'll save having to clean anything up in the test

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dry run does not work as we terminate all new-app stuff before we reach output phase. And it makes sense as we dont have what to "expose"

	if !o.Action.Verbose() || o.Action.DryRun {
		return nil
	}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah - then do you need to add some os::cmd::expect_success 'oc delete all --selector="label=something"' lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added one more new small template as reusing old ones was causing lot of false/positives.
+Added cleaning... This file is so sensitive... you touch one test and 5 starts failing :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@jim-minter
Copy link
Contributor

/retest

@jim-minter
Copy link
Contributor

@bparees I think this is nearly there - want to take a look?

@jim-minter
Copy link
Contributor

@mangirdaz you can/should squash your commits before this gets merged, use git rebase -i master and change the 2nd-last "pick"s to "fixup". If you accidentally mess things up, read up on git reflog, it's a lifesaver.

@@ -373,6 +374,10 @@ func (o *NewAppOptions) RunNewApp() error {
hasMissingRepo = true
fmt.Fprintf(out, "%sWARNING: No Docker registry has been configured with the server. Automatic builds and deployments may not function.\n", indent)
}
case *routeapi.Route:
if len(t.Spec.Host) > 0 {
fmt.Fprintf(out, "%sAccess your application via route '%s' \n", indent, t.Spec.Host)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we find a route object it's possible Host will be empty because the template.Route didn't specify a value. (which means it'll get filled in by the server when the Route object is created). This is where we should really be polling the created object on the server until it has a valid Host value filled in, and then report that value (similar to how your added readiness check works).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we will create blocking process here? Should we poll the server for let's say 5s and if we cant get it we either error or dont print it at all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes i think a cap on how long to wait is a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about this? Sorry for stupid question. Stil trying to get my head around on different implementations styles around the codebase.

// getRouteHost will poll server for host field to be populated. With timout
func getRouteHost(c *newcmd.AppConfig, r *routeapi.Route) (*routeapi.Route, error) {
	var route *routeapi.Route
	c1 := make(chan string, 1)
	go func() {
		time.Sleep(time.Second * RoutePollTimoutSeconds)
		c1 <- "Route creation timout"
	}()

	select {
	case res := <-c1:
		return nil, err.New(res)
	case <-time.After(time.Microsecond * 500):
		route, err := c.OSClient.Routes(r.Namespace).Get(r.Name, metav1.GetOptions{})
		if err != nil {
			return nil, err
		}
		if route.Spec.Host != "" {
			return route, nil
		}
	}
	return route, nil
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check out wait.Poll as it's used elsewhere in the codebase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@openshift-ci-robot openshift-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Sep 20, 2017
@mjudeikis mjudeikis changed the title [WIP] Route creation with oc new-app Route creation with oc new-app Sep 21, 2017
@openshift-ci-robot openshift-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Sep 21, 2017
if len(t.Spec.Host) > 0 {
containsRoute = true
var route *routeapi.Route
//check if route processing was complted and host field is prepopulated by router
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/compltd/completed/

if route.Spec.Host != "" {
return true, nil
}
return false, coreerror.New(fmt.Sprintf("Timout while polling route %s", t.Name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be return false, nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@bparees
Copy link
Contributor

bparees commented Sep 21, 2017

lgtm. @smarterclayton any final concerns?

"github.com/openshift/origin/pkg/util"
)

// NewAppRecommendedCommandName is the recommended command name.
const NewAppRecommendedCommandName = "new-app"

// RoutePollTimoutSeconds sets how long new-app command waits for route host to be prepopulated
const RoutePollTimoutSeconds = 5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const RoutePollTimeout = 5 * time.Second

@@ -2,6 +2,7 @@ package cmd

import (
"bytes"
coreerror "errors"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi: very rare in our codebase to rename core go imports, best avoided. We'll get rid of this import below

@@ -373,6 +379,27 @@ func (o *NewAppOptions) RunNewApp() error {
hasMissingRepo = true
fmt.Fprintf(out, "%sWARNING: No Docker registry has been configured with the server. Automatic builds and deployments may not function.\n", indent)
}
case *routeapi.Route:
if len(t.Spec.Host) > 0 {
containsRoute = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move containsRoute = true outside the if statement

err := wait.PollImmediate(500*time.Millisecond, time.Second*RoutePollTimoutSeconds, func() (bool, error) {
route, err = config.OSClient.Routes(t.Namespace).Get(t.Name, metav1.GetOptions{})
if err != nil {
return false, coreerror.New(fmt.Sprintf("Error while polling route %s", t.Name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi: fmt.Errorf == errors.New(fmt.Sprintf(...))
but here, just return the error without wrapping it -- you're wrapping it in line 398

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@bparees
Copy link
Contributor

bparees commented Sep 22, 2017

/approve
( @jim-minter or @smarterclayton can merge this w/ a lgtm)

@openshift-merge-robot openshift-merge-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 22, 2017
@jim-minter
Copy link
Contributor

/lgtm
thanks @mangirdaz !!

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Sep 22, 2017
@openshift-merge-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: bparees, jim-minter, mangirdaz

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@openshift-merge-robot
Copy link
Contributor

Automatic merge from submit-queue

@openshift-merge-robot openshift-merge-robot merged commit 3618de2 into openshift:master Sep 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants