Skip to content

Commit be45584

Browse files
committed
Add create ingress command to cmd/kubectl
Add `create ingress` unit tests Move src code to staging dir Update create command to reflect new API Replaced deprecated `extensions` api with `networking` Fix `missing strict dependencies` Update BUILD Update BUILD Fix commit conflict with upstream Update after review * Removed obsolete files * Moved v1beta to v1 api Fixed gofmt Fixed deps imports Merge with PR kubernetes#94327 Revert changes Revert go.mod Revert BUILD No need to update generated BUILD Add required deps to BUILD Update BUILD
1 parent e799c85 commit be45584

File tree

4 files changed

+358
-0
lines changed

4 files changed

+358
-0
lines changed

staging/src/k8s.io/kubectl/pkg/cmd/create/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ go_library(
99
"create_configmap.go",
1010
"create_cronjob.go",
1111
"create_deployment.go",
12+
"create_ingress.go",
1213
"create_job.go",
1314
"create_namespace.go",
1415
"create_pdb.go",
@@ -28,6 +29,7 @@ go_library(
2829
"//staging/src/k8s.io/api/batch/v1:go_default_library",
2930
"//staging/src/k8s.io/api/batch/v1beta1:go_default_library",
3031
"//staging/src/k8s.io/api/core/v1:go_default_library",
32+
"//staging/src/k8s.io/api/networking/v1:go_default_library",
3133
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
3234
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
3335
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
@@ -45,6 +47,7 @@ go_library(
4547
"//staging/src/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
4648
"//staging/src/k8s.io/client-go/kubernetes/typed/batch/v1beta1:go_default_library",
4749
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
50+
"//staging/src/k8s.io/client-go/kubernetes/typed/networking/v1:go_default_library",
4851
"//staging/src/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
4952
"//staging/src/k8s.io/component-base/cli/flag:go_default_library",
5053
"//staging/src/k8s.io/kubectl/pkg/cmd/util:go_default_library",
@@ -69,6 +72,7 @@ go_test(
6972
"create_configmap_test.go",
7073
"create_cronjob_test.go",
7174
"create_deployment_test.go",
75+
"create_ingress_test.go",
7276
"create_job_test.go",
7377
"create_namespace_test.go",
7478
"create_pdb_test.go",
@@ -87,6 +91,7 @@ go_test(
8791
"//staging/src/k8s.io/api/batch/v1:go_default_library",
8892
"//staging/src/k8s.io/api/batch/v1beta1:go_default_library",
8993
"//staging/src/k8s.io/api/core/v1:go_default_library",
94+
"//staging/src/k8s.io/api/networking/v1:go_default_library",
9095
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
9196
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
9297
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",

staging/src/k8s.io/kubectl/pkg/cmd/create/create.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cob
152152
cmd.AddCommand(NewCmdCreatePriorityClass(f, ioStreams))
153153
cmd.AddCommand(NewCmdCreateJob(f, ioStreams))
154154
cmd.AddCommand(NewCmdCreateCronJob(f, ioStreams))
155+
cmd.AddCommand(NewCmdCreateIngress(f, ioStreams))
155156
return cmd
156157
}
157158

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package create
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"strconv"
23+
24+
"github.com/spf13/cobra"
25+
26+
"k8s.io/api/networking/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
"k8s.io/apimachinery/pkg/runtime"
29+
"k8s.io/cli-runtime/pkg/genericclioptions"
30+
"k8s.io/cli-runtime/pkg/resource"
31+
networkingv1client "k8s.io/client-go/kubernetes/typed/networking/v1"
32+
cmdutil "k8s.io/kubectl/pkg/cmd/util"
33+
"k8s.io/kubectl/pkg/scheme"
34+
"k8s.io/kubectl/pkg/util/i18n"
35+
"k8s.io/kubectl/pkg/util/templates"
36+
)
37+
38+
var (
39+
ingressLong = templates.LongDesc(i18n.T(`
40+
Create an ingress with the specified name.`))
41+
42+
ingressExample = templates.Examples(i18n.T(`
43+
# Create a new ingress named my-app.
44+
kubectl create ingress my-app --host=foo.bar.com --service-name=my-svc`))
45+
)
46+
47+
// CreateIngressOptions is returned by NewCmdCreateIngress
48+
type CreateIngressOptions struct {
49+
PrintFlags *genericclioptions.PrintFlags
50+
51+
PrintObj func(obj runtime.Object) error
52+
53+
Name string
54+
Host string
55+
ServiceName string
56+
ServicePort string
57+
Path string
58+
59+
Namespace string
60+
Client *networkingv1client.NetworkingV1Client
61+
DryRunStrategy cmdutil.DryRunStrategy
62+
DryRunVerifier *resource.DryRunVerifier
63+
Builder *resource.Builder
64+
Cmd *cobra.Command
65+
66+
genericclioptions.IOStreams
67+
}
68+
69+
// NewCreateCreateIngressOptions creates and returns an instance of CreateIngressOptions
70+
func NewCreateCreateIngressOptions(ioStreams genericclioptions.IOStreams) *CreateIngressOptions {
71+
return &CreateIngressOptions{
72+
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
73+
IOStreams: ioStreams,
74+
}
75+
}
76+
77+
// NewCmdCreateIngress is a macro command to create a new ingress.
78+
func NewCmdCreateIngress(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
79+
o := NewCreateCreateIngressOptions(ioStreams)
80+
81+
cmd := &cobra.Command{
82+
Use: "ingress NAME --host=hostname| --service-name=servicename [--service-port=serviceport] [--path=path] [--dry-run]",
83+
Aliases: []string{"ing"},
84+
Short: i18n.T("Create an ingress with the specified name."),
85+
Long: ingressLong,
86+
Example: ingressExample,
87+
Run: func(cmd *cobra.Command, args []string) {
88+
cmdutil.CheckErr(o.Complete(f, cmd, args))
89+
cmdutil.CheckErr(o.Validate())
90+
cmdutil.CheckErr(o.Run())
91+
},
92+
}
93+
94+
o.PrintFlags.AddFlags(cmd)
95+
96+
cmdutil.AddApplyAnnotationFlags(cmd)
97+
cmdutil.AddValidateFlags(cmd)
98+
cmdutil.AddDryRunFlag(cmd)
99+
cmd.Flags().StringVar(&o.Host, "host", o.Host, i18n.T("Host name this Ingress should route traffic on"))
100+
cmd.Flags().StringVar(&o.ServiceName, "service-name", o.ServiceName, i18n.T("Service this Ingress should route traffic to"))
101+
cmd.Flags().StringVar(&o.ServicePort, "service-port", o.ServicePort, "Port name or number of the Service to route traffic to")
102+
cmd.Flags().StringVar(&o.Path, "path", o.Path, "Path on which to route traffic to")
103+
cmd.MarkFlagRequired("host")
104+
cmd.MarkFlagRequired("service-name")
105+
return cmd
106+
}
107+
108+
// Complete completes all the options
109+
func (o *CreateIngressOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
110+
name, err := NameFromCommandArgs(cmd, args)
111+
if err != nil {
112+
return err
113+
}
114+
o.Name = name
115+
116+
clientConfig, err := f.ToRESTConfig()
117+
if err != nil {
118+
return err
119+
}
120+
o.Client, err = networkingv1client.NewForConfig(clientConfig)
121+
if err != nil {
122+
return err
123+
}
124+
125+
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
126+
if err != nil {
127+
return err
128+
}
129+
o.Builder = f.NewBuilder()
130+
o.Cmd = cmd
131+
132+
o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
133+
if err != nil {
134+
return err
135+
}
136+
dynamicClient, err := f.DynamicClient()
137+
if err != nil {
138+
return err
139+
}
140+
discoveryClient, err := f.ToDiscoveryClient()
141+
if err != nil {
142+
return err
143+
}
144+
o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient)
145+
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
146+
printer, err := o.PrintFlags.ToPrinter()
147+
if err != nil {
148+
return err
149+
}
150+
o.PrintObj = func(obj runtime.Object) error {
151+
return printer.PrintObj(obj, o.Out)
152+
}
153+
154+
return nil
155+
}
156+
157+
func (o *CreateIngressOptions) Validate() error {
158+
return nil
159+
}
160+
161+
// Run performs the execution of 'create ingress' sub command
162+
func (o *CreateIngressOptions) Run() error {
163+
var ingress *v1.Ingress
164+
ingress = o.createIngress()
165+
166+
if o.DryRunStrategy != cmdutil.DryRunClient {
167+
createOptions := metav1.CreateOptions{}
168+
if o.DryRunStrategy == cmdutil.DryRunServer {
169+
if err := o.DryRunVerifier.HasSupport(ingress.GroupVersionKind()); err != nil {
170+
return err
171+
}
172+
createOptions.DryRun = []string{metav1.DryRunAll}
173+
}
174+
var err error
175+
ingress, err = o.Client.Ingresses(o.Namespace).Create(context.TODO(), ingress, createOptions)
176+
if err != nil {
177+
return fmt.Errorf("failed to create ingress: %v", err)
178+
}
179+
}
180+
181+
return o.PrintObj(ingress)
182+
}
183+
184+
func (o *CreateIngressOptions) createIngress() *v1.Ingress {
185+
i := &v1.Ingress{
186+
TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.String(), Kind: "Ingress"},
187+
ObjectMeta: metav1.ObjectMeta{
188+
Name: o.Name,
189+
},
190+
Spec: v1.IngressSpec{
191+
Rules: []v1.IngressRule{
192+
{
193+
Host: o.Host,
194+
IngressRuleValue: v1.IngressRuleValue{
195+
HTTP: &v1.HTTPIngressRuleValue{
196+
Paths: []v1.HTTPIngressPath{
197+
{
198+
Path: o.Path,
199+
Backend: v1.IngressBackend{
200+
Service: &v1.IngressServiceBackend{
201+
Name: o.ServiceName,
202+
},
203+
},
204+
},
205+
},
206+
},
207+
},
208+
},
209+
},
210+
},
211+
}
212+
213+
var port v1.ServiceBackendPort
214+
if n, err := strconv.Atoi(o.ServicePort); err != nil {
215+
port.Name = o.ServicePort
216+
} else {
217+
port.Number = int32(n)
218+
}
219+
220+
i.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].Backend.Service.Port = port
221+
222+
return i
223+
}

0 commit comments

Comments
 (0)