Add duplicate port validation, update devfile libraries, and add tests to check port name matches endpoint name (#5407)

* Add duplicate port validation, update devfile libraries, and add tests to check port name matches endpoint name

* Fix k8s test
This commit is contained in:
Parthvi Vala
2022-02-09 21:29:54 +05:30
committed by GitHub
parent 905b4d7533
commit 752c9285df
28 changed files with 364 additions and 179 deletions

4
go.mod
View File

@@ -7,8 +7,8 @@ require (
github.com/Netflix/go-expect v0.0.0-20201125194554-85d881c3777e
github.com/Xuanwo/go-locale v1.0.0
github.com/blang/semver v3.5.1+incompatible
github.com/devfile/api/v2 v2.0.0-20211118170330-959f3c8007c3
github.com/devfile/library v1.2.1-0.20211207205254-de570f015d84
github.com/devfile/api/v2 v2.0.0-20220126144139-f6d7cd85a481
github.com/devfile/library v1.2.1-0.20220201022328-58ef0b78c0fe
github.com/devfile/registry-support/index/generator v0.0.0-20211012185733-0a73f866043f
github.com/devfile/registry-support/registry-library v0.0.0-20211125162259-d7edf148d3e2
github.com/fatih/color v1.10.0

9
go.sum
View File

@@ -262,11 +262,12 @@ github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/devfile/api/v2 v2.0.0-20210910153124-da620cd1a7a1/go.mod h1:kLX/nW93gigOHXK3NLeJL2fSS/sgEe+OHu8bo3aoOi4=
github.com/devfile/api/v2 v2.0.0-20211118170330-959f3c8007c3 h1:G7TIrgpGx5lcZ3X7bpQeVCeeeO7tv6SAzPPvB9ThHXE=
github.com/devfile/api/v2 v2.0.0-20211118170330-959f3c8007c3/go.mod h1:d99eTN6QxgzihOOFyOZA+VpUyD4Q1pYRYHZ/ci9J96Q=
github.com/devfile/api/v2 v2.0.0-20220117162434-6e6e6a8bc14c/go.mod h1:d99eTN6QxgzihOOFyOZA+VpUyD4Q1pYRYHZ/ci9J96Q=
github.com/devfile/api/v2 v2.0.0-20220126144139-f6d7cd85a481 h1:G4trvnLOua7AsSetNa8k4u9VUNavPIwXa3CNfBwQwx4=
github.com/devfile/api/v2 v2.0.0-20220126144139-f6d7cd85a481/go.mod h1:kLX/nW93gigOHXK3NLeJL2fSS/sgEe+OHu8bo3aoOi4=
github.com/devfile/library v1.1.1-0.20210910214722-7c5ff63711ec/go.mod h1:svPWwWb+BP15SXCHl0dyOeE4Sohrjl5a2BaOzc/riLc=
github.com/devfile/library v1.2.1-0.20211207205254-de570f015d84 h1:9Tce6BIw9PCdA1AopHxVo0gheU+dP3jfl2MgBKLnMRQ=
github.com/devfile/library v1.2.1-0.20211207205254-de570f015d84/go.mod h1:qSS0cLIKTyysdkvGr4cMlTOHO0zkoobFcfvAVPtoq5Y=
github.com/devfile/library v1.2.1-0.20220201022328-58ef0b78c0fe h1:IzpRD2XS7m7k+6lFLYjaFAPYy0CSv0861teFvzNFkdM=
github.com/devfile/library v1.2.1-0.20220201022328-58ef0b78c0fe/go.mod h1:Fp8wxWPVA5pz8geGIp0DioGVgnZAdwyqsgohvRaR5rk=
github.com/devfile/registry-support/index/generator v0.0.0-20211012185733-0a73f866043f h1:fKNUmoOPh7yAs69uMRZWHvev+m3e7T4jBL/hOXZB9ys=
github.com/devfile/registry-support/index/generator v0.0.0-20211012185733-0a73f866043f/go.mod h1:bLGagbW2SFn7jo5+kUPlCMehIGqWkRtLKc5O0OyJMJM=
github.com/devfile/registry-support/registry-library v0.0.0-20211125162259-d7edf148d3e2 h1:Rwuc0bdx8xSZWdIwXjAxaKYnZIWHneJmDAAZ6a5jXzY=

View File

@@ -15,7 +15,7 @@ import (
"github.com/redhat-developer/odo/pkg/util"
)
//getPorts gets the ports from devfile
// getPorts gets the ports from devfile
func (ei *EnvInfo) getPorts(container string) ([]string, error) {
var portList []string
containerComponents, err := ei.devfileObj.Data.GetDevfileContainerComponents(common.DevfileOptions{})
@@ -42,7 +42,7 @@ func (ei *EnvInfo) getPorts(container string) ([]string, error) {
return portList, nil
}
//GetContainerPorts returns list of the ports of specified container, if it exists
// GetContainerPorts returns list of the ports of specified container, if it exists
func (ei *EnvInfo) GetContainerPorts(container string) ([]string, error) {
if container == "" {
return nil, fmt.Errorf("please provide a container")
@@ -50,12 +50,12 @@ func (ei *EnvInfo) GetContainerPorts(container string) ([]string, error) {
return ei.getPorts(container)
}
//GetComponentPorts returns all unique ports declared in all the containers
// GetComponentPorts returns all unique ports declared in all the containers
func (ei *EnvInfo) GetComponentPorts() ([]string, error) {
return ei.getPorts("")
}
//checkValidPort checks and retrieves valid port from devfile when no port is specified
// checkValidPort checks and retrieves valid port from devfile when no port is specified
func (ei *EnvInfo) checkValidPort(url *localConfigProvider.LocalURL, portsOf string, ports []string) (err error) {
if url.Port == -1 {
if len(ports) > 1 {
@@ -191,7 +191,11 @@ func (ei *EnvInfo) ValidateURL(url localConfigProvider.LocalURL) error {
}
for _, endpoint := range component.Container.Endpoints {
if endpoint.Name == url.Name && !ei.updateURL {
return fmt.Errorf("url %v already exist in devfile endpoint entry under container %v", url.Name, component.Name)
return fmt.Errorf("url %v already exists in devfile endpoint entry under container %q", url.Name, component.Name)
}
// Check for a duplicate port entry
if endpoint.TargetPort == url.Port && !ei.updateURL {
return fmt.Errorf("port %v already exists in devfile endpoint entry under container %q", url.Port, component.Name)
}
containerPortMap[endpoint.TargetPort] = component.Name
}

View File

@@ -520,11 +520,7 @@ func TestEnvInfo_ValidateURL(t *testing.T) {
fields: fields{
devfileObj: odoTestingUtil.GetTestDevfileObj(fs),
componentSettings: ComponentSettings{
URL: &[]localConfigProvider.LocalURL{
{
Name: "port-3030",
},
},
URL: &[]localConfigProvider.LocalURL{},
},
},
args: args{
@@ -616,6 +612,39 @@ func TestEnvInfo_ValidateURL(t *testing.T) {
updateURL: true,
wantErr: false,
},
{
name: "case 14: create a new url with a port that already exists in a devfile endpoint",
fields: fields{
devfileObj: odoTestingUtil.GetTestDevfileObj(fs),
componentSettings: ComponentSettings{
URL: &[]localConfigProvider.LocalURL{},
},
},
args: args{
url: localConfigProvider.LocalURL{
Name: "myport",
Port: 3000,
},
},
wantErr: true,
},
{
name: "case 15: update url with a port that already exists in a devfile endpoint",
fields: fields{
devfileObj: odoTestingUtil.GetTestDevfileObj(fs),
componentSettings: ComponentSettings{
URL: &[]localConfigProvider.LocalURL{},
},
},
args: args{
url: localConfigProvider.LocalURL{
Port: 3000,
Host: "something.com",
},
},
wantErr: false,
updateURL: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -173,10 +173,10 @@ var _ = Describe("odo devfile delete command tests", func() {
resourceTypes := []string{helper.ResourceTypeDeployment, helper.ResourceTypePod, helper.ResourceTypeService, helper.ResourceTypeIngress, helper.ResourceTypePVC}
BeforeEach(func() {
helper.Cmd("odo", "url", "create", "example", "--host", "1.2.3.4.nip.io", "--port", "3000", "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", "example", "--host", "1.2.3.4.nip.io", "--port", "3030", "--ingress").ShouldPass()
if os.Getenv("KUBERNETES") != "true" {
helper.Cmd("odo", "url", "create", "example-1", "--port", "3000").ShouldPass()
helper.Cmd("odo", "url", "create", "example-1", "--port", "4000").ShouldPass()
resourceTypes = append(resourceTypes, helper.ResourceTypeRoute)
}
})

View File

@@ -16,6 +16,16 @@ import (
var _ = Describe("odo devfile url command tests", func() {
var componentName string
var commonVar helper.CommonVar
url1 := helper.RandString(5)
url1Port := "5000"
url2 := helper.RandString(5)
url2Port := "9000"
// Required to ensure duplicate ports are not used to create a URL
nodejsDevfilePort := "3000"
nodejsDevfileURLName := "3000-tcp"
springbootDevfilePort := "8080"
portNumber := "3030"
host := helper.RandString(5) + ".com"
// This is run before every Spec (It)
var _ = BeforeEach(func() {
@@ -35,7 +45,7 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("creating a Nodejs component", func() {
stdout := ""
var stdout string
BeforeEach(func() {
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
@@ -43,37 +53,40 @@ var _ = Describe("odo devfile url command tests", func() {
})
It("should not allow creating an invalid host", func() {
stdout = helper.Cmd("odo", "url", "create", "--host", "https://127.0.0.1:60104", "--port", "3000", "--ingress").ShouldFail().Err()
stdout = helper.Cmd("odo", "url", "create", "--host", "https://127.0.0.1:60104", "--port", portNumber, "--ingress").ShouldFail().Err()
Expect(stdout).To(ContainSubstring("is not a valid host name"))
})
It("should not allow using tls secret if url is not secure", func() {
stdout = helper.Cmd("odo", "url", "create", "--tls-secret", "foo", "--port", "3000", "--ingress").ShouldFail().Err()
stdout = helper.Cmd("odo", "url", "create", "--tls-secret", "foo", "--port", portNumber, "--ingress").ShouldFail().Err()
Expect(stdout).To(ContainSubstring("TLS secret is only available for secure URLs of Ingress kind"))
})
It("should report multiple issues when it's the case", func() {
stdout = helper.Cmd("odo", "url", "create", "--host", "https://127.0.0.1:60104", "--tls-secret", "foo", "--port", "3000", "--ingress").ShouldFail().Err()
stdout = helper.Cmd("odo", "url", "create", "--host", "https://127.0.0.1:60104", "--tls-secret", "foo", "--port", portNumber, "--ingress").ShouldFail().Err()
Expect(stdout).To(And(ContainSubstring("is not a valid host name"), ContainSubstring("TLS secret is only available for secure URLs of Ingress kind")))
})
It("should not allow to create URL with duplicate port", func() {
stdout = helper.Cmd("odo", "url", "create", url1, "--port", nodejsDevfilePort).ShouldFail().Err()
Expect(stdout).To(ContainSubstring("port 3000 already exists in devfile endpoint entry"))
})
It("should not allow creating under an invalid container", func() {
containerName := helper.RandString(5)
stdout = helper.Cmd("odo", "url", "create", "--host", "com", "--port", "3000", "--container", containerName, "--ingress").ShouldFail().Err()
stdout = helper.Cmd("odo", "url", "create", "--host", "com", "--port", portNumber, "--container", containerName, "--ingress").ShouldFail().Err()
helper.MatchAllInOutput(stdout, []string{"container", containerName, "not exist"})
})
It("should not allow creating an endpoint with same name", func() {
stdout = helper.Cmd("odo", "url", "create", "3000-tcp", "--host", "com", "--port", "3000", "--ingress").ShouldFail().Err()
Expect(stdout).To(ContainSubstring("url 3000-tcp already exist in devfile endpoint entry"))
stdout = helper.Cmd("odo", "url", "create", nodejsDevfileURLName, "--host", "com", "--port", nodejsDevfilePort, "--ingress").ShouldFail().Err()
Expect(stdout).To(ContainSubstring(fmt.Sprintf("url %s already exists in devfile endpoint entry", nodejsDevfileURLName)))
})
When("creating ingress url1 with port flag and doing odo push", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
url2 := "nodejs-project-3000-" + helper.RandString(5)
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--port", "9090", "--host", host, "--secure", "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--secure", "--ingress").ShouldPass()
helper.Cmd("odo", "push").ShouldPass()
})
@@ -81,10 +94,14 @@ var _ = Describe("odo devfile url command tests", func() {
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "ingress"})
})
It("should take user provided url name", func() {
stdout = string(commonVar.CliRunner.Run("get", "svc", "--namespace", commonVar.Project, fmt.Sprintf("%v-%v", componentName, "app"), "-ojsonpath='{.spec.ports[*].name}'").Out.Contents())
Expect(stdout).To(ContainSubstring(url1))
})
When("creating ingress url2 with port flag and doing odo push", func() {
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url2, "--port", "8080", "--host", host, "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url2, "--port", url2Port, "--host", host, "--ingress").ShouldPass()
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
})
It("should check state of url2", func() {
@@ -103,21 +120,19 @@ var _ = Describe("odo devfile url command tests", func() {
})
})
When("creating a url with -o json", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
var createExpected []string
var createValues []gjson.Result
var createJSON string
BeforeEach(func() {
helper.Cmd("odo", "url", "delete", "3000-tcp", "-f").ShouldPass()
createJSON = helper.Cmd("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress", "-o", "json").ShouldPass().Out()
helper.Cmd("odo", "url", "delete", nodejsDevfileURLName, "-f").ShouldPass()
createJSON = helper.Cmd("odo", "url", "create", url1, "--port", nodejsDevfilePort, "--host", host, "--ingress", "-o", "json").ShouldPass().Out()
})
It("should validate machine readable output for url create", func() {
createValues = gjson.GetMany(createJSON, "kind", "metadata.name", "spec.port", "status.state")
createExpected = []string{"URL", url1, "3000", "Not Pushed"}
createExpected = []string{"URL", url1, nodejsDevfilePort, "Not Pushed"}
Expect(helper.GjsonMatcher(createValues, createExpected)).To(Equal(true))
})
@@ -139,9 +154,9 @@ var _ = Describe("odo devfile url command tests", func() {
})
})
When("creating a URL without port flag", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
XWhen("creating a URL without port flag", func() {
// marking it as pending, since we want to start using port number as a key to URLs in devfile,
// FIXME: and odo should not allow using url create without a port number, this should be taken care of in v3-alpha2
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--host", host, "--ingress").ShouldPass()
@@ -151,11 +166,10 @@ var _ = Describe("odo devfile url command tests", func() {
helper.MatchAllInOutput(stdout, []string{url1, "3000", "Not Pushed"})
})
})
When("creating a secure URL and doing odo push", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--port", "9090", "--host", host, "--secure", "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--secure", "--ingress").ShouldPass()
stdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
})
It("should list secure URL", func() {
@@ -166,10 +180,8 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("create with now flag", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
BeforeEach(func() {
stdout = helper.Cmd("odo", "url", "create", url1, "--port", "3000", "--host", host, "--now", "--ingress").ShouldPass().Out()
stdout = helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--now", "--ingress").ShouldPass().Out()
})
It("should check if url created for component", func() {
// check the env for the runMode
@@ -190,10 +202,8 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("creating a url and doing odo push twice", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--ingress").ShouldPass()
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
stdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
})
@@ -215,10 +225,8 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("creating URL with path flag", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--port", "8090", "--host", host, "--path", "testpath", "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--path", "testpath", "--ingress").ShouldPass()
stdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
})
It("should create URL with path defined in Endpoint", func() {
@@ -227,10 +235,7 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("executing odo outside of context", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
subFolderContext := ""
url2 := ""
BeforeEach(func() {
subFolderContext = filepath.Join(commonVar.Context, helper.RandString(6))
helper.MakeDir(subFolderContext)
@@ -238,19 +243,18 @@ var _ = Describe("odo devfile url command tests", func() {
})
It("should fail if url is created from non context dir", func() {
stdout = helper.Cmd("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress").ShouldFail().Err()
stdout = helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--ingress").ShouldFail().Err()
Expect(stdout).To(ContainSubstring("the current directory does not represent an odo component"))
})
It("should fail if host flag not provided with ingress flag", func() {
stdout = helper.Cmd("odo", "url", "create", url1, "--port", "3000", "--ingress", "--context", commonVar.Context).ShouldFail().Err()
stdout = helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--ingress", "--context", commonVar.Context).ShouldFail().Err()
Expect(stdout).To(ContainSubstring("host must be provided"))
})
When("creating url1,url2 and doing odo push with context flag", func() {
BeforeEach(func() {
url2 = "nodejs-project-3000-" + helper.RandString(5)
helper.Cmd("odo", "url", "create", url2, "--port", "3000", "--host", host, "--ingress", "--context", commonVar.Context).ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress", "--context", commonVar.Context).ShouldPass()
helper.Cmd("odo", "url", "create", url2, "--port", url2Port, "--host", host, "--ingress", "--context", commonVar.Context).ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--ingress", "--context", commonVar.Context).ShouldPass()
stdout = helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out()
})
It("should successfully push url1 and url2", func() {
@@ -270,19 +274,16 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("creating a java-springboot component", func() {
stdout := ""
var stdout string
BeforeEach(func() {
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "springboot", "devfile.yaml")).ShouldPass()
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
})
When("create URLs under different container names", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
url2 := helper.RandString(5)
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--port", "8080", "--host", host, "--container", "runtime", "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url2, "--port", "9090", "--host", host, "--container", "tools", "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--container", "runtime", "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url2, "--port", url2Port, "--host", host, "--container", "tools", "--ingress").ShouldPass()
stdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
})
It("should create URLs under different container names", func() {
@@ -290,27 +291,24 @@ var _ = Describe("odo devfile url command tests", func() {
})
})
When("create URLs under different container names with same port number", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
XWhen("create URLs under different container names with same port number", func() {
// marking it as pending, since the current behavior of odo url create is buggy, this should be fixed in odo v3-alpha2
BeforeEach(func() {
stdout = helper.Cmd("odo", "url", "create", url1, "--port", "8080", "--host", host, "--container", "tools", "--ingress").ShouldFail().Err()
})
It("should not create URLs under different container names with same port number", func() {
helper.MatchAllInOutput(stdout, []string{fmt.Sprintf("cannot set URL %s under container tools", url1), "TargetPort 8080 is being used under container runtime"})
helper.MatchAllInOutput(stdout, []string{fmt.Sprintf("cannot set URL %s under container tools", url1), fmt.Sprintf("TargetPort %s is being used under container runtime", springbootDevfilePort)})
})
})
})
When("Creating nodejs component and url with .devfile.yaml", func() {
url1 := helper.RandString(5)
host := helper.RandString(5) + ".com"
stdout := ""
var stdout string
BeforeEach(func() {
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, ".devfile.yaml"))
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName).ShouldPass()
helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context)
stdout = helper.Cmd("odo", "url", "create", url1, "--port", "8080", "--host", host, "--container", "runtime", "--ingress").ShouldPass().Out()
stdout = helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--host", host, "--container", "runtime", "--ingress").ShouldPass().Out()
})
It("should create url", func() {
@@ -336,10 +334,7 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("creating a nodejs component", func() {
url1 := helper.RandString(5)
ingressurl := helper.RandString(5)
host := helper.RandString(5) + ".com"
BeforeEach(func() {
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass()
@@ -347,30 +342,25 @@ var _ = Describe("odo devfile url command tests", func() {
})
It("should error out when a host is provided with a route on a openShift cluster", func() {
output := helper.Cmd("odo", "url", "create", url1, "--host", "com", "--port", "3000").ShouldFail().Err()
output := helper.Cmd("odo", "url", "create", url1, "--host", "com", "--port", portNumber).ShouldFail().Err()
Expect(output).To(ContainSubstring("host is not supported"))
})
When("creating multiple url with different state", func() {
url2 := helper.RandString(5)
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--port", "9090", "--secure").ShouldPass()
helper.Cmd("odo", "url", "create", ingressurl, "--port", "8080", "--host", host, "--ingress").ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", url1Port, "--secure").ShouldPass()
helper.Cmd("odo", "url", "create", ingressurl, "--port", portNumber, "--host", host, "--ingress").ShouldPass()
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
helper.Cmd("odo", "url", "create", url2, "--port", "8080").ShouldPass()
helper.Cmd("odo", "url", "create", url2, "--port", url2Port).ShouldPass()
})
It("should list route and ingress urls with appropriate state", func() {
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "route"})
helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "route"})
helper.MatchAllInOutput(stdout, []string{ingressurl, "Pushed", "false", "ingress"})
})
When("url1 is deleted locally", func() {
BeforeEach(func() {
@@ -386,19 +376,34 @@ var _ = Describe("odo devfile url command tests", func() {
})
})
When("should create a automatically route on a openShift cluster", func() {
XIt("should automatically create route on a openShift cluster", func() {
// marking it as pending, since current odo url create behavior is buggy, and this should be taken care of in v3-alpha2
helper.Cmd("odo", "url", "create", url1, "--port", nodejsDevfilePort).ShouldPass()
fileOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
Expect(err).To(BeNil())
helper.MatchAllInOutput(fileOutput, []string{nodejsDevfileURLName, nodejsDevfilePort})
})
When("doing odo push twice and doing url list", func() {
var pushstdout string
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--port", "3000").ShouldPass()
fileOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
Expect(err).To(BeNil())
helper.MatchAllInOutput(fileOutput, []string{"3000-tcp", "3000"})
helper.Cmd("odo", "url", "create", url1, "--port", url1Port).ShouldPass()
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
pushstdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
})
When("doing odo push twice and doing url list", func() {
pushstdout := ""
It("should push successfully", func() {
helper.DontMatchAllInOutput(pushstdout, []string{"successfully deleted", "created"})
Expect(pushstdout).To(ContainSubstring("URLs are synced with the cluster, no changes are required"))
Expect(stdout).Should(ContainSubstring(url1))
})
When("deleting the url1 and doing odo push twice and doing url list", func() {
BeforeEach(func() {
helper.Cmd("odo", "url", "delete", url1, "-f").ShouldPass()
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
pushstdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
@@ -407,23 +412,7 @@ var _ = Describe("odo devfile url command tests", func() {
It("should push successfully", func() {
helper.DontMatchAllInOutput(pushstdout, []string{"successfully deleted", "created"})
Expect(pushstdout).To(ContainSubstring("URLs are synced with the cluster, no changes are required"))
Expect(stdout).Should(ContainSubstring(url1))
})
When("deleting the url1 and doing odo push twice and doing url list", func() {
BeforeEach(func() {
helper.Cmd("odo", "url", "delete", url1, "-f").ShouldPass()
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
pushstdout = helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out()
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
})
It("should push successfully", func() {
helper.DontMatchAllInOutput(pushstdout, []string{"successfully deleted", "created"})
Expect(pushstdout).To(ContainSubstring("URLs are synced with the cluster, no changes are required"))
Expect(stdout).ShouldNot(ContainSubstring(url1))
})
Expect(stdout).ShouldNot(ContainSubstring(url1))
})
})
})
@@ -433,39 +422,37 @@ var _ = Describe("odo devfile url command tests", func() {
helper.MatchAllInOutput(stdout, []string{"URL 3000-tcp", "created"})
stdout = helper.Cmd("odo", "url", "list").ShouldPass().Out()
})
It("should create a route on a openShift cluster without calling url create", func() {
Expect(stdout).Should(ContainSubstring("3000-tcp"))
})
})
})
})
When("creating a python component", func() {
url1 := helper.RandString(5)
When("creating a python component", func() {
BeforeEach(func() {
helper.CopyExample(filepath.Join("source", "python"), commonVar.Context)
helper.Chdir(commonVar.Context)
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "python", "devfile-registry.yaml")).ShouldPass()
})
When("creating a url and doing odo push", func() {
var output string
BeforeEach(func() {
helper.CopyExample(filepath.Join("source", "python"), commonVar.Context)
helper.Chdir(commonVar.Context)
helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "python", "devfile-registry.yaml")).ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--port", "5000", "--host", "com", "--ingress").ShouldPass()
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
})
When("creating a url and doing odo push", func() {
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1).ShouldPass()
helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass()
})
It("should create a url for a unsupported devfile component", func() {
output := helper.Cmd("odo", "url", "list").ShouldPass().Out()
Expect(output).Should(ContainSubstring(url1))
})
It("should create a url for a unsupported devfile component", func() {
output = helper.Cmd("odo", "url", "list").ShouldPass().Out()
Expect(output).Should(ContainSubstring(url1))
})
})
})
Context("Testing URLs for Kubernetes specific scenarios", func() {
XContext("Testing URLs for Kubernetes specific scenarios", func() {
// TODO: marking it as pending, since current odo url create behavior is buggy, and this should be taken care of in v3-alpha2
BeforeEach(func() {
if os.Getenv("KUBERNETES") != "true" {
Skip("This is a Kubernetes specific scenario, skipping")
@@ -479,22 +466,20 @@ var _ = Describe("odo devfile url command tests", func() {
})
When("creating url", func() {
url1 := helper.RandString(5)
BeforeEach(func() {
helper.Cmd("odo", "url", "create", "--host", "com", "--port", "3000").ShouldPass()
helper.Cmd("odo", "url", "create", "--host", "com", "--port", nodejsDevfilePort).ShouldPass()
})
When("creating a second url", func() {
BeforeEach(func() {
helper.Cmd("odo", "url", "create", url1, "--host", "com", "--port", "8080").ShouldPass()
helper.Cmd("odo", "url", "create", url1, "--host", "com", "--port", url1Port).ShouldPass()
})
It("should use an existing URL when there are URLs with no host defined in the env file with same port", func() {
fileOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
Expect(err).To(BeNil())
helper.MatchAllInOutput(fileOutput, []string{url1, "8080"})
helper.MatchAllInOutput(fileOutput, []string{url1, url1Port})
count := strings.Count(fileOutput, "targetPort")
Expect(count).To(Equal(2))
})
@@ -502,7 +487,7 @@ var _ = Describe("odo devfile url command tests", func() {
It("should verify", func() {
fileOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, "devfile.yaml"))
Expect(err).To(BeNil())
helper.MatchAllInOutput(fileOutput, []string{"3000-tcp", "3000"})
helper.MatchAllInOutput(fileOutput, []string{nodejsDevfileURLName, nodejsDevfilePort})
count := strings.Count(fileOutput, "targetPort")
Expect(count).To(Equal(1))
})

View File

@@ -92,7 +92,7 @@ type CommandUnion struct {
//
// When no `apply` command exist for a given component,
// it is assumed the component will be applied at devworkspace start
// by default.
// by default, unless `deployByDefault` for that component is set to false.
// +optional
Apply *ApplyCommand `json:"apply,omitempty"`

View File

@@ -25,6 +25,7 @@ type Image struct {
}
// +union
// +devfile:getter:generate
type ImageUnion struct {
// Type of image
//
@@ -35,4 +36,11 @@ type ImageUnion struct {
// Allows specifying dockerfile type build
// +optional
Dockerfile *DockerfileImage `json:"dockerfile,omitempty"`
// Defines if the image should be built during startup.
//
// Default value is `false`
// +optional
// +devfile:default:value=false
AutoBuild *bool `json:"autoBuild,omitempty"`
}

View File

@@ -28,10 +28,19 @@ type K8sLikeComponentLocation struct {
Inlined string `json:"inlined,omitempty"`
}
// +devfile:getter:generate
type K8sLikeComponent struct {
BaseComponent `json:",inline"`
K8sLikeComponentLocation `json:",inline"`
Endpoints []Endpoint `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
// Defines if the component should be deployed during startup.
//
// Default value is `false`
// +optional
// +devfile:default:value=false
DeployByDefault *bool `json:"deployByDefault,omitempty"`
Endpoints []Endpoint `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
}
// Component that allows partly importing Kubernetes resources into the devworkspace POD

View File

@@ -6,7 +6,7 @@ import (
// Devfile describes the structure of a cloud-native devworkspace and development environment.
// +k8s:deepcopy-gen=false
// +devfile:jsonschema:generate:omitCustomUnionMembers=true,omitPluginUnionMembers=true
// +devfile:jsonschema:generate:omitCustomUnionMembers=true,omitPluginUnionMembers=true,shortenEndpointNameLength=true
type Devfile struct {
devfile.DevfileHeader `json:",inline"`

View File

@@ -50,6 +50,7 @@ type Endpoint struct {
// +kubebuilder:validation:MaxLength=63
Name string `json:"name"`
// The port number should be unique.
TargetPort int `json:"targetPort"`
// Describes how the endpoint should be exposed on the network.

View File

@@ -1,3 +1,4 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// Code generated by controller-gen. DO NOT EDIT.
@@ -2839,6 +2840,11 @@ func (in *ImageUnion) DeepCopyInto(out *ImageUnion) {
*out = new(DockerfileImage)
(*in).DeepCopyInto(*out)
}
if in.AutoBuild != nil {
in, out := &in.AutoBuild, &out.AutoBuild
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageUnion.
@@ -2859,6 +2865,11 @@ func (in *ImageUnionParentOverride) DeepCopyInto(out *ImageUnionParentOverride)
*out = new(DockerfileImageParentOverride)
(*in).DeepCopyInto(*out)
}
if in.AutoBuild != nil {
in, out := &in.AutoBuild, &out.AutoBuild
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageUnionParentOverride.
@@ -2879,6 +2890,11 @@ func (in *ImageUnionPluginOverride) DeepCopyInto(out *ImageUnionPluginOverride)
*out = new(DockerfileImagePluginOverride)
(*in).DeepCopyInto(*out)
}
if in.AutoBuild != nil {
in, out := &in.AutoBuild, &out.AutoBuild
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageUnionPluginOverride.
@@ -2899,6 +2915,11 @@ func (in *ImageUnionPluginOverrideParentOverride) DeepCopyInto(out *ImageUnionPl
*out = new(DockerfileImagePluginOverrideParentOverride)
(*in).DeepCopyInto(*out)
}
if in.AutoBuild != nil {
in, out := &in.AutoBuild, &out.AutoBuild
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageUnionPluginOverrideParentOverride.
@@ -2988,6 +3009,11 @@ func (in *K8sLikeComponent) DeepCopyInto(out *K8sLikeComponent) {
*out = *in
out.BaseComponent = in.BaseComponent
out.K8sLikeComponentLocation = in.K8sLikeComponentLocation
if in.DeployByDefault != nil {
in, out := &in.DeployByDefault, &out.DeployByDefault
*out = new(bool)
**out = **in
}
if in.Endpoints != nil {
in, out := &in.Endpoints, &out.Endpoints
*out = make([]Endpoint, len(*in))
@@ -3072,6 +3098,11 @@ func (in *K8sLikeComponentParentOverride) DeepCopyInto(out *K8sLikeComponentPare
*out = *in
out.BaseComponentParentOverride = in.BaseComponentParentOverride
out.K8sLikeComponentLocationParentOverride = in.K8sLikeComponentLocationParentOverride
if in.DeployByDefault != nil {
in, out := &in.DeployByDefault, &out.DeployByDefault
*out = new(bool)
**out = **in
}
if in.Endpoints != nil {
in, out := &in.Endpoints, &out.Endpoints
*out = make([]EndpointParentOverride, len(*in))
@@ -3096,6 +3127,11 @@ func (in *K8sLikeComponentPluginOverride) DeepCopyInto(out *K8sLikeComponentPlug
*out = *in
out.BaseComponentPluginOverride = in.BaseComponentPluginOverride
out.K8sLikeComponentLocationPluginOverride = in.K8sLikeComponentLocationPluginOverride
if in.DeployByDefault != nil {
in, out := &in.DeployByDefault, &out.DeployByDefault
*out = new(bool)
**out = **in
}
if in.Endpoints != nil {
in, out := &in.Endpoints, &out.Endpoints
*out = make([]EndpointPluginOverride, len(*in))
@@ -3120,6 +3156,11 @@ func (in *K8sLikeComponentPluginOverrideParentOverride) DeepCopyInto(out *K8sLik
*out = *in
out.BaseComponentPluginOverrideParentOverride = in.BaseComponentPluginOverrideParentOverride
out.K8sLikeComponentLocationPluginOverrideParentOverride = in.K8sLikeComponentLocationPluginOverrideParentOverride
if in.DeployByDefault != nil {
in, out := &in.DeployByDefault, &out.DeployByDefault
*out = new(bool)
**out = **in
}
if in.Endpoints != nil {
in, out := &in.Endpoints, &out.Endpoints
*out = make([]EndpointPluginOverrideParentOverride, len(*in))

View File

@@ -20,11 +20,21 @@ func (in *Container) GetDedicatedPod() bool {
return getBoolOrDefault(in.DedicatedPod, false)
}
// GetAutoBuild returns the value of the boolean property. If unset, it's the default value specified in the devfile:default:value marker
func (in *ImageUnion) GetAutoBuild() bool {
return getBoolOrDefault(in.AutoBuild, false)
}
// GetRootRequired returns the value of the boolean property. If unset, it's the default value specified in the devfile:default:value marker
func (in *Dockerfile) GetRootRequired() bool {
return getBoolOrDefault(in.RootRequired, false)
}
// GetDeployByDefault returns the value of the boolean property. If unset, it's the default value specified in the devfile:default:value marker
func (in *K8sLikeComponent) GetDeployByDefault() bool {
return getBoolOrDefault(in.DeployByDefault, false)
}
// GetEphemeral returns the value of the boolean property. If unset, it's the default value specified in the devfile:default:value marker
func (in *Volume) GetEphemeral() bool {
return getBoolOrDefault(in.Ephemeral, false)

View File

@@ -229,7 +229,7 @@ type CommandUnionParentOverride struct {
//
// When no `apply` command exist for a given component,
// it is assumed the component will be applied at devworkspace start
// by default.
// by default, unless `deployByDefault` for that component is set to false.
// +optional
Apply *ApplyCommandParentOverride `json:"apply,omitempty"`
@@ -444,6 +444,7 @@ type EndpointParentOverride struct {
Name string `json:"name"`
// +optional
// The port number should be unique.
TargetPort int `json:"targetPort,omitempty"`
// Describes how the endpoint should be exposed on the network.
@@ -512,7 +513,14 @@ type EndpointParentOverride struct {
type K8sLikeComponentParentOverride struct {
BaseComponentParentOverride `json:",inline"`
K8sLikeComponentLocationParentOverride `json:",inline"`
Endpoints []EndpointParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
// Defines if the component should be deployed during startup.
//
// Default value is `false`
// +optional
DeployByDefault *bool `json:"deployByDefault,omitempty"`
Endpoints []EndpointParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
}
// Volume that should be mounted to a component container
@@ -657,7 +665,7 @@ type K8sLikeComponentLocationParentOverride struct {
// +union
type ImageUnionParentOverride struct {
// +kubebuilder:validation:Enum=Dockerfile
// +kubebuilder:validation:Enum=Dockerfile;AutoBuild
// Type of image
//
// +unionDiscriminator
@@ -667,6 +675,12 @@ type ImageUnionParentOverride struct {
// Allows specifying dockerfile type build
// +optional
Dockerfile *DockerfileImageParentOverride `json:"dockerfile,omitempty"`
// Defines if the image should be built during startup.
//
// Default value is `false`
// +optional
AutoBuild *bool `json:"autoBuild,omitempty"`
}
// Location from where the an import reference is retrieved
@@ -844,7 +858,7 @@ type CommandUnionPluginOverrideParentOverride struct {
//
// When no `apply` command exist for a given component,
// it is assumed the component will be applied at devworkspace start
// by default.
// by default, unless `deployByDefault` for that component is set to false.
// +optional
Apply *ApplyCommandPluginOverrideParentOverride `json:"apply,omitempty"`
@@ -1126,6 +1140,7 @@ type EndpointPluginOverrideParentOverride struct {
Name string `json:"name"`
// +optional
// The port number should be unique.
TargetPort int `json:"targetPort,omitempty"`
// Describes how the endpoint should be exposed on the network.
@@ -1194,7 +1209,14 @@ type EndpointPluginOverrideParentOverride struct {
type K8sLikeComponentPluginOverrideParentOverride struct {
BaseComponentPluginOverrideParentOverride `json:",inline"`
K8sLikeComponentLocationPluginOverrideParentOverride `json:",inline"`
Endpoints []EndpointPluginOverrideParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
// Defines if the component should be deployed during startup.
//
// Default value is `false`
// +optional
DeployByDefault *bool `json:"deployByDefault,omitempty"`
Endpoints []EndpointPluginOverrideParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
}
// Volume that should be mounted to a component container
@@ -1294,7 +1316,7 @@ type K8sLikeComponentLocationPluginOverrideParentOverride struct {
// +union
type ImageUnionPluginOverrideParentOverride struct {
// +kubebuilder:validation:Enum=Dockerfile
// +kubebuilder:validation:Enum=Dockerfile;AutoBuild
// Type of image
//
// +unionDiscriminator
@@ -1304,6 +1326,12 @@ type ImageUnionPluginOverrideParentOverride struct {
// Allows specifying dockerfile type build
// +optional
Dockerfile *DockerfileImagePluginOverrideParentOverride `json:"dockerfile,omitempty"`
// Defines if the image should be built during startup.
//
// Default value is `false`
// +optional
AutoBuild *bool `json:"autoBuild,omitempty"`
}
type BaseCommandPluginOverrideParentOverride struct {

View File

@@ -123,7 +123,7 @@ type CommandUnionPluginOverride struct {
//
// When no `apply` command exist for a given component,
// it is assumed the component will be applied at devworkspace start
// by default.
// by default, unless `deployByDefault` for that component is set to false.
// +optional
Apply *ApplyCommandPluginOverride `json:"apply,omitempty"`
@@ -314,6 +314,7 @@ type EndpointPluginOverride struct {
Name string `json:"name"`
// +optional
// The port number should be unique.
TargetPort int `json:"targetPort,omitempty"`
// Describes how the endpoint should be exposed on the network.
@@ -382,7 +383,14 @@ type EndpointPluginOverride struct {
type K8sLikeComponentPluginOverride struct {
BaseComponentPluginOverride `json:",inline"`
K8sLikeComponentLocationPluginOverride `json:",inline"`
Endpoints []EndpointPluginOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
// Defines if the component should be deployed during startup.
//
// Default value is `false`
// +optional
DeployByDefault *bool `json:"deployByDefault,omitempty"`
Endpoints []EndpointPluginOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
}
// Volume that should be mounted to a component container
@@ -481,7 +489,7 @@ type K8sLikeComponentLocationPluginOverride struct {
// +union
type ImageUnionPluginOverride struct {
// +kubebuilder:validation:Enum=Dockerfile
// +kubebuilder:validation:Enum=Dockerfile;AutoBuild
// Type of image
//
// +unionDiscriminator
@@ -491,6 +499,12 @@ type ImageUnionPluginOverride struct {
// Allows specifying dockerfile type build
// +optional
Dockerfile *DockerfileImagePluginOverride `json:"dockerfile,omitempty"`
// Defines if the image should be built during startup.
//
// Default value is `false`
// +optional
AutoBuild *bool `json:"autoBuild,omitempty"`
}
type BaseCommandPluginOverride struct {

View File

@@ -45,6 +45,7 @@ func (union *ImageUnion) Simplify() {
// +k8s:deepcopy-gen=false
type ImageUnionVisitor struct {
Dockerfile func(*DockerfileImage) error
AutoBuild func(*bool) error
}
var dockerfileSrc reflect.Type = reflect.TypeOf(DockerfileSrcVisitor{})
@@ -267,6 +268,7 @@ func (union *ImageUnionParentOverride) Simplify() {
// +k8s:deepcopy-gen=false
type ImageUnionParentOverrideVisitor struct {
Dockerfile func(*DockerfileImageParentOverride) error
AutoBuild func(*bool) error
}
var importReferenceUnionParentOverride reflect.Type = reflect.TypeOf(ImportReferenceUnionParentOverrideVisitor{})
@@ -398,6 +400,7 @@ func (union *ImageUnionPluginOverrideParentOverride) Simplify() {
// +k8s:deepcopy-gen=false
type ImageUnionPluginOverrideParentOverrideVisitor struct {
Dockerfile func(*DockerfileImagePluginOverrideParentOverride) error
AutoBuild func(*bool) error
}
var dockerfileSrcPluginOverrideParentOverride reflect.Type = reflect.TypeOf(DockerfileSrcPluginOverrideParentOverrideVisitor{})
@@ -507,6 +510,7 @@ func (union *ImageUnionPluginOverride) Simplify() {
// +k8s:deepcopy-gen=false
type ImageUnionPluginOverrideVisitor struct {
Dockerfile func(*DockerfileImagePluginOverride) error
AutoBuild func(*bool) error
}
var dockerfileSrcPluginOverride reflect.Type = reflect.TypeOf(DockerfileSrcPluginOverrideVisitor{})

View File

@@ -5,24 +5,18 @@ import "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
// validateEndpoints checks if
// 1. all the endpoint names are unique across components
// 2. endpoint port are unique across component containers
// ie; two component containers cannot have the same target port but two endpoints
// in a single component container can have the same target port
func validateEndpoints(endpoints []v1alpha2.Endpoint, processedEndPointPort map[int]bool, processedEndPointName map[string]bool) (errList []error) {
currentComponentEndPointPort := make(map[int]bool)
for _, endPoint := range endpoints {
if _, ok := processedEndPointName[endPoint.Name]; ok {
errList = append(errList, &InvalidEndpointError{name: endPoint.Name})
}
if _, ok := processedEndPointPort[endPoint.TargetPort]; ok {
errList = append(errList, &InvalidEndpointError{port: endPoint.TargetPort})
}
processedEndPointName[endPoint.Name] = true
currentComponentEndPointPort[endPoint.TargetPort] = true
processedEndPointPort[endPoint.TargetPort] = true
}
for targetPort := range currentComponentEndPointPort {
if _, ok := processedEndPointPort[targetPort]; ok {
errList = append(errList, &InvalidEndpointError{port: targetPort})
}
processedEndPointPort[targetPort] = true
}
return errList
}

View File

@@ -96,7 +96,7 @@ func (e *InvalidEndpointError) Error() string {
if e.name != "" {
errMsg = fmt.Sprintf("devfile contains multiple endpoint entries with same name: %v", e.name)
} else if fmt.Sprint(e.port) != "" {
errMsg = fmt.Sprintf("devfile contains multiple containers with same TargetPort: %v", e.port)
errMsg = fmt.Sprintf("devfile contains multiple endpoint entries with same TargetPort: %v", e.port)
}
return errMsg

View File

@@ -14,8 +14,7 @@ The validation will be done as part of schema validation, the rule will be intro
### Endpoints:
- all the endpoint names are unique across components
Since network is shared in the same pod, endpoint ports should be unique across components, two components cannot have the same target port but two endpoints in a single component can have the same target port. Only exception: container component with `dedicatedpod=true`
- all the endpoint ports are unique across components. Only exception: container component with `dedicatedpod=true`
### Commands:
1. id must be unique

View File

@@ -46,7 +46,12 @@ func convertPorts(endpoints []v1.Endpoint) []corev1.ContainerPort {
} else {
portProtocol = corev1.ProtocolTCP
}
name := fmt.Sprintf("%d-%s", portNumber, strings.ToLower(string(portProtocol)))
name := endpoint.Name
if len(name) > 15 {
// to be compatible with endpoint longer than 15 chars
name = fmt.Sprintf("port-%v", portNumber)
}
if _, exist := portMap[name]; !exist {
portMap[name] = true
containerPorts = append(containerPorts, corev1.ContainerPort{
@@ -268,7 +273,6 @@ func getServiceSpec(devfileObj parser.DevfileObj, selectorLabels map[string]stri
}
// if Exposure == none, should not create a service for that port
if !portExist && portExposureMap[int(port.ContainerPort)] != v1.NoneEndpointExposure {
port.Name = fmt.Sprintf("port-%v", port.ContainerPort)
containerPorts = append(containerPorts, port)
}
}

View File

@@ -41,7 +41,7 @@ const JsonSchema220 = `{
],
"properties": {
"apply": {
"description": "Command that consists in applying a given component definition, typically bound to a devworkspace event.\n\nFor example, when an 'apply' command is bound to a 'preStart' event, and references a 'container' component, it will start the container as a K8S initContainer in the devworkspace POD, unless the component has its 'dedicatedPod' field set to 'true'.\n\nWhen no 'apply' command exist for a given component, it is assumed the component will be applied at devworkspace start by default.",
"description": "Command that consists in applying a given component definition, typically bound to a devworkspace event.\n\nFor example, when an 'apply' command is bound to a 'preStart' event, and references a 'container' component, it will start the container as a K8S initContainer in the devworkspace POD, unless the component has its 'dedicatedPod' field set to 'true'.\n\nWhen no 'apply' command exist for a given component, it is assumed the component will be applied at devworkspace start by default, unless 'deployByDefault' for that component is set to false.",
"type": "object",
"required": [
"component"
@@ -347,7 +347,7 @@ const JsonSchema220 = `{
},
"name": {
"type": "string",
"maxLength": 63,
"maxLength": 15,
"pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
},
"path": {
@@ -372,6 +372,7 @@ const JsonSchema220 = `{
"type": "boolean"
},
"targetPort": {
"description": "The port number should be unique.",
"type": "integer"
}
},
@@ -457,6 +458,10 @@ const JsonSchema220 = `{
}
],
"properties": {
"autoBuild": {
"description": "Defines if the image should be built during startup.\n\nDefault value is 'false'",
"type": "boolean"
},
"dockerfile": {
"description": "Allows specifying dockerfile type build",
"type": "object",
@@ -577,6 +582,10 @@ const JsonSchema220 = `{
}
],
"properties": {
"deployByDefault": {
"description": "Defines if the component should be deployed during startup.\n\nDefault value is 'false'",
"type": "boolean"
},
"endpoints": {
"type": "array",
"items": {
@@ -610,7 +619,7 @@ const JsonSchema220 = `{
},
"name": {
"type": "string",
"maxLength": 63,
"maxLength": 15,
"pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
},
"path": {
@@ -635,6 +644,7 @@ const JsonSchema220 = `{
"type": "boolean"
},
"targetPort": {
"description": "The port number should be unique.",
"type": "integer"
}
},
@@ -674,6 +684,10 @@ const JsonSchema220 = `{
}
],
"properties": {
"deployByDefault": {
"description": "Defines if the component should be deployed during startup.\n\nDefault value is 'false'",
"type": "boolean"
},
"endpoints": {
"type": "array",
"items": {
@@ -707,7 +721,7 @@ const JsonSchema220 = `{
},
"name": {
"type": "string",
"maxLength": 63,
"maxLength": 15,
"pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
},
"path": {
@@ -732,6 +746,7 @@ const JsonSchema220 = `{
"type": "boolean"
},
"targetPort": {
"description": "The port number should be unique.",
"type": "integer"
}
},
@@ -935,7 +950,7 @@ const JsonSchema220 = `{
],
"properties": {
"apply": {
"description": "Command that consists in applying a given component definition, typically bound to a devworkspace event.\n\nFor example, when an 'apply' command is bound to a 'preStart' event, and references a 'container' component, it will start the container as a K8S initContainer in the devworkspace POD, unless the component has its 'dedicatedPod' field set to 'true'.\n\nWhen no 'apply' command exist for a given component, it is assumed the component will be applied at devworkspace start by default.",
"description": "Command that consists in applying a given component definition, typically bound to a devworkspace event.\n\nFor example, when an 'apply' command is bound to a 'preStart' event, and references a 'container' component, it will start the container as a K8S initContainer in the devworkspace POD, unless the component has its 'dedicatedPod' field set to 'true'.\n\nWhen no 'apply' command exist for a given component, it is assumed the component will be applied at devworkspace start by default, unless 'deployByDefault' for that component is set to false.",
"type": "object",
"properties": {
"component": {
@@ -1219,7 +1234,7 @@ const JsonSchema220 = `{
},
"name": {
"type": "string",
"maxLength": 63,
"maxLength": 15,
"pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
},
"path": {
@@ -1243,6 +1258,7 @@ const JsonSchema220 = `{
"type": "boolean"
},
"targetPort": {
"description": "The port number should be unique.",
"type": "integer"
}
},
@@ -1320,9 +1336,18 @@ const JsonSchema220 = `{
"required": [
"dockerfile"
]
},
{
"required": [
"autoBuild"
]
}
],
"properties": {
"autoBuild": {
"description": "Defines if the image should be built during startup.\n\nDefault value is 'false'",
"type": "boolean"
},
"dockerfile": {
"description": "Allows specifying dockerfile type build",
"type": "object",
@@ -1437,6 +1462,10 @@ const JsonSchema220 = `{
}
],
"properties": {
"deployByDefault": {
"description": "Defines if the component should be deployed during startup.\n\nDefault value is 'false'",
"type": "boolean"
},
"endpoints": {
"type": "array",
"items": {
@@ -1468,7 +1497,7 @@ const JsonSchema220 = `{
},
"name": {
"type": "string",
"maxLength": 63,
"maxLength": 15,
"pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
},
"path": {
@@ -1492,6 +1521,7 @@ const JsonSchema220 = `{
"type": "boolean"
},
"targetPort": {
"description": "The port number should be unique.",
"type": "integer"
}
},
@@ -1531,6 +1561,10 @@ const JsonSchema220 = `{
}
],
"properties": {
"deployByDefault": {
"description": "Defines if the component should be deployed during startup.\n\nDefault value is 'false'",
"type": "boolean"
},
"endpoints": {
"type": "array",
"items": {
@@ -1562,7 +1596,7 @@ const JsonSchema220 = `{
},
"name": {
"type": "string",
"maxLength": 63,
"maxLength": 15,
"pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
},
"path": {
@@ -1586,6 +1620,7 @@ const JsonSchema220 = `{
"type": "boolean"
},
"targetPort": {
"description": "The port number should be unique.",
"type": "integer"
}
},

View File

@@ -43,7 +43,9 @@ func (d *DevfileV2) GetCommands(options common.DevfileOptions) ([]v1.Command, er
continue
}
commands = append(commands, command)
if options.FilterByName == "" || command.Id == options.FilterByName {
commands = append(commands, command)
}
}
return commands, nil

View File

@@ -20,6 +20,9 @@ type DevfileOptions struct {
// ProjectOptions specifies the various options available to filter projects/starterProjects
ProjectOptions ProjectOptions
// FilterByName specifies the name for the particular devfile object that's been looking for
FilterByName string
}
// CommandOptions specifies the various options available to filter commands

View File

@@ -35,7 +35,9 @@ func (d *DevfileV2) GetComponents(options common.DevfileOptions) ([]v1.Component
continue
}
components = append(components, component)
if options.FilterByName == "" || component.Name == options.FilterByName {
components = append(components, component)
}
}
return components, nil

View File

@@ -33,8 +33,9 @@ func (d *DevfileV2) GetProjects(options common.DevfileOptions) ([]v1.Project, er
if options.ProjectOptions.ProjectSourceType != "" && projectSourceType != options.ProjectOptions.ProjectSourceType {
continue
}
projects = append(projects, project)
if options.FilterByName == "" || project.Name == options.FilterByName {
projects = append(projects, project)
}
}
return projects, nil
@@ -118,7 +119,9 @@ func (d *DevfileV2) GetStarterProjects(options common.DevfileOptions) ([]v1.Star
continue
}
starterProjects = append(starterProjects, starterProject)
if options.FilterByName == "" || starterProject.Name == options.FilterByName {
starterProjects = append(starterProjects, starterProject)
}
}
return starterProjects, nil

View File

@@ -549,10 +549,16 @@ func setDefaults(d DevfileObj) (err error) {
} else if component.Kubernetes != nil {
endpoints = component.Kubernetes.Endpoints
if devfileVersion != string(data.APISchemaVersion200) && devfileVersion != string(data.APISchemaVersion210) {
val := component.Kubernetes.GetDeployByDefault()
component.Kubernetes.DeployByDefault = &val
}
} else if component.Openshift != nil {
endpoints = component.Openshift.Endpoints
if devfileVersion != string(data.APISchemaVersion200) && devfileVersion != string(data.APISchemaVersion210) {
val := component.Openshift.GetDeployByDefault()
component.Openshift.DeployByDefault = &val
}
} else if component.Volume != nil && devfileVersion != string(data.APISchemaVersion200) {
volume := component.Volume
@@ -565,6 +571,8 @@ func setDefaults(d DevfileObj) (err error) {
val := dockerImage.GetRootRequired()
dockerImage.RootRequired = &val
}
val := component.Image.GetAutoBuild()
component.Image.AutoBuild = &val
}
if endpoints != nil {

View File

@@ -126,7 +126,7 @@ type DockerImageValues struct {
//GetDockerImageTestComponent returns a docker image component that is used for testing.
//The parameters allow customization of the content. If they are set to nil, then the properties will not be set
func GetDockerImageTestComponent(div DockerImageValues, attr attributes.Attributes) v1.Component {
func GetDockerImageTestComponent(div DockerImageValues, autobuild *bool, attr attributes.Attributes) v1.Component {
comp := v1.Component{
Name: "image",
ComponentUnion: v1.ComponentUnion{
@@ -134,6 +134,7 @@ func GetDockerImageTestComponent(div DockerImageValues, attr attributes.Attribut
Image: v1.Image{
ImageName: div.ImageName,
ImageUnion: v1.ImageUnion{
AutoBuild: autobuild,
Dockerfile: &v1.DockerfileImage{
DockerfileSrc: v1.DockerfileSrc{
Uri: div.Uri,

4
vendor/modules.txt vendored
View File

@@ -96,7 +96,7 @@ github.com/deislabs/oras/pkg/artifact
github.com/deislabs/oras/pkg/content
github.com/deislabs/oras/pkg/context
github.com/deislabs/oras/pkg/oras
# github.com/devfile/api/v2 v2.0.0-20211118170330-959f3c8007c3
# github.com/devfile/api/v2 v2.0.0-20220126144139-f6d7cd85a481
## explicit
github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2
github.com/devfile/api/v2/pkg/attributes
@@ -105,7 +105,7 @@ github.com/devfile/api/v2/pkg/utils/overriding
github.com/devfile/api/v2/pkg/utils/unions
github.com/devfile/api/v2/pkg/validation
github.com/devfile/api/v2/pkg/validation/variables
# github.com/devfile/library v1.2.1-0.20211207205254-de570f015d84
# github.com/devfile/library v1.2.1-0.20220201022328-58ef0b78c0fe
## explicit
github.com/devfile/library/pkg/devfile
github.com/devfile/library/pkg/devfile/generator