-
Notifications
You must be signed in to change notification settings - Fork 244
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
create services together with deployment during devfile push #2679
create services together with deployment during devfile push #2679
Conversation
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
Hi @yangcao77. Thanks for your PR. I'm waiting for a openshift member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Codecov Report
@@ Coverage Diff @@
## master #2679 +/- ##
==========================================
+ Coverage 43.39% 43.74% +0.35%
==========================================
Files 86 87 +1
Lines 7907 7967 +60
==========================================
+ Hits 3431 3485 +54
- Misses 4136 4143 +7
+ Partials 340 339 -1
Continue to review full report at Codecov.
|
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
/ok-to-test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yangcao77 Can you please add integration test for the changes. The test will be mostly user facing scenario like what you describe in How to test changes
of your pr description.
How to write:
Create a separate test file, for example devfile_test.go
in tests/integration/
devfile_test.go
package integration
import (
"os"
"path/filepath"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/openshift/odo/tests/helper"
)
var _ = Describe("odo storage command tests", func() {
var project string
var context string
// This is run after every Spec (It)
var _ = BeforeEach(func() {
SetDefaultEventuallyTimeout(10 * time.Minute)
SetDefaultConsistentlyDuration(30 * time.Second)
context = helper.CreateNewContext()
os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
project = helper.CreateRandProject()
oc = helper.NewOcRunner("oc")
})
// Clean up after the test
// This is run after every Spec (It)
var _ = AfterEach(func() {
helper.DeleteProject(project)
helper.DeleteDir(context)
os.Unsetenv("GLOBALODOCONFIG")
})
Context("when running devfile push", func() {
It("should create services together with deployment", func() {
helper.CmdShouldPass("git", "clone", "https://github.com/rajivnathan/openLibertyDevfile", filepath.Join(context,"openLibertyDevfile"))
helper.CmdShouldPass("odo", "preference", "set", "experimental", "true")
helper.CmdShouldPass("odo", "push", "--devfile", filepath.Join(context,"openLibertyDevfile","devfile.yaml"))
// modify the port number to 8080 in devfile. You need to write a
// new helper function in tests/integration/helper/helper_filesystem.go
// and call it here for example helper.yamlupdate()
helper.CmdShouldPass("odo", "push", "--devfile", filepath.Join(context,"openLibertyDevfile","devfile.yaml"))
// verify Describe the service using oc command, verify the port has been changed to 8080
})
})
})
Basically we use ginkgo framework for integration test. You can visit ginkgo documentation for more details - https://onsi.github.io/ginkgo/ plus go through odo integration tests here in tests/integration/
for how we have been doing it. I am sure you will get more tips for writing the integration test.
@amitkrout We do not have any integration tests for devfile support yet. The integration tests will be added later on. We have an issue opened to track that: #2673 |
Understood. Thanks |
|
||
service, err := c.KubeClient.CoreV1().Services(c.Namespace).Create(&svc) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "unable to create Service for %s", commonObjectMeta.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is wrapping error is necessary here?? IMO we should return bare errors from client functions, as they are intended to be called my multiple functions and it helps in checking conditions based on error codes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm following the error format for all the other functions under pkg/kclient (pod.go, volumes.go, deployments.go).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ya I see, resolving it for your PR :), will raise a separate concern.
/test v4.1-integration-e2e-benchmark |
This PR currently blocks the work for #2592 which is targeted for sprint 180. |
/refresh |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if two containers expose the same port it fails
▶ odo push
• Push devfile component spring-boot-http-booster ...
✗ Failed to start component with name spring-boot-http-booster.
Error: Failed to start the component: unable to update Service for spring-boot-http-booster: Service "spring-boot-http-booster" is invalid: [spec.ports[1].name: Duplicate value: "8080-tcp", spec.ports[1]: Duplicate value: core.ServicePort{Name:"", Protocol:"TCP", Port:8080, TargetPort:intstr.IntOrString{Type:0, IntVal:0, StrVal:""}, NodePort:0}]
devfile.yaml
apiVersion: 1.0.0
metadata:
name: test
components:
- type: dockerimage
alias: tools
image: quay.io/eclipse/che-java8-maven:nightly
memoryLimit: 768Mi
endpoints:
- name: "8080/tcp"
port: 8080
mountSources: true
volumes:
- name: m2
containerPath: /home/user/.m2
- type: dockerimage
alias: tools2
image: quay.io/eclipse/che-java8-maven:nightly
memoryLimit: 768Mi
endpoints:
- name: "8080/tcp"
port: 8080
mountSources: true
volumes:
- name: m2
containerPath: /home/user/.m2
commands:
- name: build
actions:
- type: exec
component: tools
command: "mvn clean install"
- name: run
actions:
- type: exec
component: tools
command: java-jar target/*.jar
I take this back 😇 /appprove |
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
resourceReqs := GetResourceReqs(comp) | ||
container := kclient.GenerateContainer(*comp.Alias, *comp.Image, false, comp.Command, comp.Args, envVars, resourceReqs) | ||
containers = append(containers, *container) | ||
// Only components with aliases are considered because without an alias commands cannot reference them |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think you over wrote the master changes during rebase, this logic has been moved to common.utils.go GetSupportedComponents()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you remove the comment as well, that comment is for func GetAliasedComponents()
} else { | ||
_, err = a.Client.CreateDeployment(*deploymentSpec) | ||
if err != nil { | ||
return err | ||
} | ||
glog.V(3).Infof("Successfully created component %v", componentName) | ||
_, err = a.Client.CreateService(objectMeta, *serviceSpec) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question about something you brought up before, are we creating only one service for all the components?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One service for all ports in devfile.
for _, endpoint := range endpoints { | ||
name := strings.TrimSpace(util.GetDNS1123Name(strings.ToLower(*endpoint.Name))) | ||
containerPorts = append(containerPorts, corev1.ContainerPort{ | ||
Name: name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need to be trimmed to below 63 char? I had a similar issue for "vol name", I later found out not only Kubernetes resources but other names are also capped at 63. Can you pls confirm this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out. Tested that the max length for port name is 15 characters. Push a new commit to trim it down to 15 characters.
for _, c := range deploymentSpec.Template.Spec.Containers { | ||
if len(containerPorts) == 0 { | ||
containerPorts = c.Ports | ||
} else { | ||
containerPorts = append(containerPorts, c.Ports...) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if multiple components have the same endpoint, are we appending the same thing twice here? What happens when that is passed to GenerateServiceSpec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There cannot be multiple components have the same endpoint, see Tomas's comment:
all the dockerimage components are containers in one pod, and they can't expose same port.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh ok thx, We should see if push's devfile parse validation is doing it for the endpoints or else add it in 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tomas has already tested it:
▶ odo push
• Push devfile component spring-boot-http-booster ...
✗ Failed to start component with name spring-boot-http-booster.
Error: Failed to start the component: unable to update Service for spring-boot-http-booster: Service "spring-boot-http-booster" is invalid: [spec.ports[1].name: Duplicate value: "8080-tcp", spec.ports[1]: Duplicate value: core.ServicePort{Name:"", Protocol:"TCP", Port:8080, TargetPort:intstr.IntOrString{Type:0, IntVal:0, StrVal:""}, NodePort:0}]
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: kadel The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
for _, endpoint := range endpoints { | ||
name := strings.TrimSpace(util.GetDNS1123Name(strings.ToLower(*endpoint.Name))) | ||
if len(name) > 15 { | ||
name = name[:15] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you use the util function util.TruncateString
instead here and have a const for 15
resourceReqs := GetResourceReqs(comp) | ||
container := kclient.GenerateContainer(*comp.Alias, *comp.Image, false, comp.Command, comp.Args, envVars, resourceReqs) | ||
containers = append(containers, *container) | ||
// Only components with aliases are considered because without an alias commands cannot reference them |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you remove the comment as well, that comment is for func GetAliasedComponents()
// generate Service Spec | ||
var svcPorts []corev1.ServicePort | ||
for _, containerPort := range containerPorts { | ||
svcPort := corev1.ServicePort{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we're reconverting from corev1.ContainerPort
to corev1.ServicePort
, can we just use corev1.ServicePort
in utils.go ConvertPorts()
? Then your GenerateServiceSpec()
can just take corev1.ServicePort
directly and does not need to convert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pod spec need it to be in format of corev1.ContainerPort
when we generate it use the containers returned from utils.GetContainers()
if err != nil { | ||
return err | ||
} | ||
glog.V(3).Infof("Successfully created component %v", componentName) | ||
_, err = a.Client.CreateService(objectMeta, *serviceSpec) | ||
ownerReference := kclient.GenerateOwnerReference(deployment) | ||
objectMetaTemp := objectMeta |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand why you have an objectMetaTemp
for update, but i think you dont really need it for create..
Spec: svcSpec, | ||
} | ||
|
||
service, err := c.KubeClient.CoreV1().Services(c.Namespace).Create(&svc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I tried odo push
with multiple components having the same endpoints, and i noticed that there is no devfile validation..
Services.Create()
fails because it cannot create service with two same endpoints, but this results in a deployment and a pod that is left hanging because it could not create pvc which is after service creation.
NAME READY STATUS RESTARTS AGE LABELS
pod/spring-devfile-85d64fdd5b-dxn4j 0/2 Pending 0 9s component=spring-devfile,pod-template-hash=4182098816
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE LABELS
deployment.extensions/spring-devfile 1 1 1 0 9s component=spring-devfile
Maybe we should validate the data in devfile before we do odo push
but I think we dont have it now. Could be done later with an another PR perhaps, if we want to do it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added validation for duplicate ports
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
/test v4.3-integration-e2e-benchmark |
1 similar comment
/test v4.3-integration-e2e-benchmark |
Signed-off-by: Stephanie <stephanie.cao@ibm.com>
@yangcao77 you can save some typing using /retest |
/test v4.2-integration-e2e-benchmark |
2 similar comments
/test v4.2-integration-e2e-benchmark |
/test v4.2-integration-e2e-benchmark |
/retest |
Thx for the change, works well 👍 /lgtm |
/retest Please review the full test history for this PR and help us cut down flakes. |
2 similar comments
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
What type of PR is this?
/kind feature
What does does this PR do / why we need it:
This PR creates service during devfile push using the port name and number provided within the devfile. Also updates the service if the deployment get updated.
Which issue(s) this PR fixes:
#2622
How to test changes / Special notes to the reviewer:
To test create
git clone Clone https://github.com/rajivnathan/openLibertyDevfile
Verify a service with the component name has been created.
Describe the service, verify the port matches the endpoint in the devfile.
To test update:
modify the port number to 8080 in devfile
Describe the service, verify the port has been changed to 8080