Skip to content

Commit 3618de2

Browse files
Merge pull request #16396 from mangirdaz/new-app-routes
Automatic merge from submit-queue Route creation with oc new-app 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.
2 parents 50bb01b + 9ef1268 commit 3618de2

File tree

6 files changed

+164
-0
lines changed

6 files changed

+164
-0
lines changed

pkg/oc/cli/cmd/newapp.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,16 @@ import (
4040
newcmd "github.com/openshift/origin/pkg/generate/app/cmd"
4141
"github.com/openshift/origin/pkg/generate/git"
4242
imageapi "github.com/openshift/origin/pkg/image/apis/image"
43+
routeapi "github.com/openshift/origin/pkg/route/apis/route"
4344
"github.com/openshift/origin/pkg/util"
4445
)
4546

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

50+
// RoutePollTimoutSeconds sets how long new-app command waits for route host to be prepopulated
51+
const RoutePollTimeout = 5 * time.Second
52+
4953
var (
5054
newAppLong = templates.LongDesc(`
5155
Create a new application by specifying source code, templates, and/or images
@@ -345,6 +349,7 @@ func (o *NewAppOptions) RunNewApp() error {
345349
hasMissingRepo := false
346350
installing := []*kapi.Pod{}
347351
indent := o.Action.DefaultIndent()
352+
containsRoute := false
348353
for _, item := range result.List.Items {
349354
switch t := item.(type) {
350355
case *kapi.Pod:
@@ -373,6 +378,27 @@ func (o *NewAppOptions) RunNewApp() error {
373378
hasMissingRepo = true
374379
fmt.Fprintf(out, "%sWARNING: No Docker registry has been configured with the server. Automatic builds and deployments may not function.\n", indent)
375380
}
381+
case *routeapi.Route:
382+
containsRoute = true
383+
if len(t.Spec.Host) > 0 {
384+
var route *routeapi.Route
385+
//check if route processing was completed and host field is prepopulated by router
386+
err := wait.PollImmediate(500*time.Millisecond, RoutePollTimeout, func() (bool, error) {
387+
route, err = config.OSClient.Routes(t.Namespace).Get(t.Name, metav1.GetOptions{})
388+
if err != nil {
389+
return false, fmt.Errorf("Error while polling route %s", t.Name)
390+
}
391+
if route.Spec.Host != "" {
392+
return true, nil
393+
}
394+
return false, nil
395+
})
396+
if err != nil {
397+
glog.V(4).Infof("Failed to poll route %s host field: %s", t.Name, err)
398+
} else {
399+
fmt.Fprintf(out, "%sAccess your application via route '%s' \n", indent, route.Spec.Host)
400+
}
401+
}
376402
}
377403
}
378404

@@ -385,13 +411,35 @@ func (o *NewAppOptions) RunNewApp() error {
385411
fmt.Fprintf(out, "%sTrack installation of %s with '%s logs %s'.\n", indent, installing[i].Name, o.BaseName, installing[i].Name)
386412
}
387413
case len(result.List.Items) > 0:
414+
//if we don't find a route we give a message to expose it
415+
if !containsRoute {
416+
//we if don't have any routes, but we have services - we suggest commands to expose those
417+
svc := getServices(result.List.Items)
418+
if len(svc) > 0 {
419+
fmt.Fprintf(out, "%sApplication is not exposed. You can expose services to the outside world by executing one or more of the commands below:\n", indent)
420+
for _, s := range svc {
421+
fmt.Fprintf(out, "%s '%s %s svc/%s' \n", indent, o.BaseName, ExposeRecommendedName, s.Name)
422+
}
423+
}
424+
}
388425
fmt.Fprintf(out, "%sRun '%s %s' to view your app.\n", indent, o.BaseName, StatusRecommendedName)
389426
}
390427
return nil
391428
}
392429

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

432+
func getServices(items []runtime.Object) []*kapi.Service {
433+
var svc []*kapi.Service
434+
for _, i := range items {
435+
switch i.(type) {
436+
case *kapi.Service:
437+
svc = append(svc, i.(*kapi.Service))
438+
}
439+
}
440+
return svc
441+
}
442+
395443
func followInstallation(config *newcmd.AppConfig, input string, pod *kapi.Pod, logsForObjectFn LogsForObjectFunc) error {
396444
fmt.Fprintf(config.Out, "--> Installing ...\n")
397445

pkg/oc/cli/cmd/status.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import (
2121
// StatusRecommendedName is the recommended command name.
2222
const StatusRecommendedName = "status"
2323

24+
// ExposeRecommendedName is the recommended command name to expose app.
25+
const ExposeRecommendedName = "expose"
26+
2427
var (
2528
statusLong = templates.LongDesc(`
2629
Show a high level overview of the current project

pkg/template/controller/readiness.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
buildapi "github.com/openshift/origin/pkg/build/apis/build"
1717
buildutil "github.com/openshift/origin/pkg/build/util"
1818
"github.com/openshift/origin/pkg/client"
19+
routeapi "github.com/openshift/origin/pkg/route/apis/route"
1920
)
2021

2122
// checkBuildReadiness determins if a Build is ready, failed or neither.
@@ -133,6 +134,15 @@ func checkStatefulSetReadiness(oc client.Interface, obj runtime.Object) (bool, b
133134
return ready, failed, nil
134135
}
135136

137+
// checkRouteReadiness checks if host field was prepopulated already.
138+
func checkRouteReadiness(oc client.Interface, obj runtime.Object) (bool, bool, error) {
139+
route := obj.(*routeapi.Route)
140+
ready := route.Spec.Host != ""
141+
failed := false
142+
143+
return ready, failed, nil
144+
}
145+
136146
// readinessCheckers maps GroupKinds to the appropriate function. Note that in
137147
// some cases more than one GK maps to the same function.
138148
var readinessCheckers = map[schema.GroupKind]func(client.Interface, runtime.Object) (bool, bool, error){
@@ -146,6 +156,8 @@ var readinessCheckers = map[schema.GroupKind]func(client.Interface, runtime.Obje
146156
deployapi.Kind("DeploymentConfig"): checkDeploymentConfigReadiness,
147157
batch.Kind("Job"): checkJobReadiness,
148158
apps.Kind("StatefulSet"): checkStatefulSetReadiness,
159+
routeapi.Kind("Route"): checkRouteReadiness,
160+
routeapi.LegacyKind("Route"): checkRouteReadiness,
149161
}
150162

151163
// canCheckReadiness indicates whether a readiness check exists for a GK.

pkg/template/controller/readiness_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
deployapi "github.com/openshift/origin/pkg/apps/apis/apps"
1717
buildapi "github.com/openshift/origin/pkg/build/apis/build"
1818
"github.com/openshift/origin/pkg/client/testclient"
19+
routeapi "github.com/openshift/origin/pkg/route/apis/route"
1920
)
2021

2122
func TestCheckReadiness(t *testing.T) {
@@ -224,6 +225,42 @@ func TestCheckReadiness(t *testing.T) {
224225
},
225226
expectedReady: true,
226227
},
228+
{
229+
groupKind: routeapi.Kind("Route"),
230+
object: &routeapi.Route{
231+
Spec: routeapi.RouteSpec{
232+
Host: "",
233+
},
234+
},
235+
expectedReady: false,
236+
},
237+
{
238+
groupKind: routeapi.Kind("Route"),
239+
object: &routeapi.Route{
240+
Spec: routeapi.RouteSpec{
241+
Host: "app.example.com",
242+
},
243+
},
244+
expectedReady: true,
245+
},
246+
{
247+
groupKind: routeapi.LegacyKind("Route"),
248+
object: &routeapi.Route{
249+
Spec: routeapi.RouteSpec{
250+
Host: "",
251+
},
252+
},
253+
expectedReady: false,
254+
},
255+
{
256+
groupKind: routeapi.LegacyKind("Route"),
257+
object: &routeapi.Route{
258+
Spec: routeapi.RouteSpec{
259+
Host: "app.example.com",
260+
},
261+
},
262+
expectedReady: true,
263+
},
227264
}
228265

229266
for i, test := range tests {

test/cmd/newapp.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ os::cmd::expect_success_and_text 'oc new-app mysql --dry-run' 'tag "5.7" for "my
3636
# test deployments are created with the boolean flag and printed in the UI
3737
os::cmd::expect_success_and_text 'oc new-app mysql --dry-run --as-test' 'This image will be test deployed'
3838
os::cmd::expect_success_and_text 'oc new-app mysql -o yaml --as-test' 'test: true'
39+
os::cmd::expect_success_and_text 'oc new-app test/testdata/template-minimal-expose.json --as-test' 'Access your application via route'
40+
os::cmd::expect_success 'oc delete all -l app=expose-output'
41+
os::cmd::expect_success_and_text 'oc new-app mysql --as-test' 'Application is not exposed'
42+
os::cmd::expect_success 'oc delete all -l app=mysql'
3943

4044
# test that imagestream references across imagestreams do not cause an error
4145
os::cmd::try_until_success 'oc get imagestreamtags ruby:2.3'
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"kind": "Template",
3+
"apiVersion": "v1",
4+
"metadata": {
5+
"name": "helloworld-sample"
6+
},
7+
"objects": [
8+
{
9+
"kind": "Service",
10+
"apiVersion": "v1",
11+
"metadata": {
12+
"name": "frontend"
13+
},
14+
"spec": {
15+
"ports": [
16+
{
17+
"name": "web",
18+
"protocol": "TCP",
19+
"port": 5432,
20+
"targetPort": 8080,
21+
"nodePort": 0
22+
}
23+
],
24+
"selector": {
25+
"name": "frontend"
26+
},
27+
"type": "ClusterIP",
28+
"sessionAffinity": "None"
29+
},
30+
"status": {
31+
"loadBalancer": {}
32+
}
33+
},
34+
{
35+
"kind": "Route",
36+
"apiVersion": "v1",
37+
"metadata": {
38+
"name": "route-edge",
39+
"annotations": {
40+
"template.openshift.io/expose-uri": "http://{.spec.host}{.spec.path}"
41+
}
42+
},
43+
"spec": {
44+
"host": "www.example.com",
45+
"to": {
46+
"kind": "Service",
47+
"name": "frontend"
48+
},
49+
"tls": {
50+
"termination": "edge"
51+
}
52+
},
53+
"status": {}
54+
}
55+
],
56+
"parameters": [],
57+
"labels": {
58+
"app": "expose-output"
59+
}
60+
}

0 commit comments

Comments
 (0)