Added URL support for --from-file command line flag #726
Conversation
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.
Hi @tkeech1, thank you for sending a PR for this!
I would suggest a different approach here. Instead of downloading the file with the CLI and setting the function content in the field Function
it would be better to:
- Set the content type to
url
. - Set the function content to the URL given by the user.
- In the provision container (see the method
getProvisionContainer
ink8sutil.go
), if the content type is anurl
, download the file withcurl
and decode or unzip it if the content type isurl+base64
orurl+zip
.
That way we avoid the limitation of 1MB that the CRD object has and we fix as well #655.
Another couple of small suggestions:
- You can still download the file in the CLI as well to obtain the sha256.
- We don't need to support URLs pointing to a Zip file from the CLI in the first PR, we can assume that
--from-url
will point to a plain text file for the moment.
Let us know if you need any help with that.
cmd/kubeless/function/deploy.go
Outdated
if err != nil { | ||
logrus.Fatal(err) | ||
} | ||
|
||
file, err := cmd.Flags().GetString("from-file") |
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.
we would need to throw an error if --from-url
and --from-file
are both set
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.
did you miss this comment? (not sure if it has been answered elsewhere). Actually, thinking about it, it would be better to support that the flag --from-file
supports to specify an URL. That is more similar to kubectl
that allows you to do kubectl create -f https://...
we can parse the path and discover if it is an URL.
cmd/kubeless/function/function.go
Outdated
@@ -120,6 +121,16 @@ func getFileSha256(file string) (string, error) { | |||
return "sha256:" + checksum, err | |||
} | |||
|
|||
func getHTTPSha256(bytes []byte) (string, error) { |
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.
this can be called getSha256
, there is nothing specific about HTTP here
Hi @andresmgot, |
Hi @tkeech1 , I have one more question. If the URL is say the gitlab or github URL, which needs an authentication, how are we handling the authentication? |
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.
Great! thank you for applying the changes. I see that the CI is working now. Can you add an integration test to check that the feature is working in a real environment?
For doing so you need to add, in the examples/Makefile
, a couple of tasks:
get-python-url:
kubeless function deploy get-python --runtime python2.7 --handler helloget.foo --from-file https://raw.githubusercontent.com/kubeless/kubeless/v1.0.0-alpha.1/examples/python/helloget.py
get-python-url-verify:
kubeless function call get-python |egrep hello.world
And then enable the test in the bats file tests/integration-tests.bats
@test "Deploy functions to evaluate" {
deploy_function get-python
...
+ deploy_function get-python-url
...
}
...
+@test "Test function: get-python-url" {
+ verify_function get-python-url
+ kubeless_function_delete get-python-url
+}
pkg/utils/k8sutil.go
Outdated
@@ -433,6 +433,10 @@ func getProvisionContainer(function, checksum, fileName, handler, contentType, r | |||
decodedFile := "/tmp/func.decoded" | |||
prepareCommand = appendToCommand(prepareCommand, fmt.Sprintf("base64 -d < %s > %s", originFile, decodedFile)) | |||
originFile = decodedFile | |||
} else if strings.Contains(contentType, "url") { | |||
fromURLFile := "/tmp/func.fromurl" | |||
prepareCommand = appendToCommand(prepareCommand, fmt.Sprintf("curl %s --silent --output %s", function, fromURLFile)) |
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.
Lets add -L to follow redirects
cmd/kubeless/function/deploy.go
Outdated
if err != nil { | ||
logrus.Fatal(err) | ||
} | ||
|
||
file, err := cmd.Flags().GetString("from-file") |
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.
did you miss this comment? (not sure if it has been answered elsewhere). Actually, thinking about it, it would be better to support that the flag --from-file
supports to specify an URL. That is more similar to kubectl
that allows you to do kubectl create -f https://...
we can parse the path and discover if it is an URL.
pkg/utils/k8sutil_test.go
Outdated
if !strings.HasPrefix(c.Args[0], "curl https://raw.githubusercontent.com/test/test/test/test.py --silent --output /tmp/func.fromurl") { | ||
t.Errorf("Unexpected command: %s", c.Args[0]) | ||
} | ||
|
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 add another unit test that checks that if the type is url+zip
it downloads and unzip the file?
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.
Hi @andresmgot,
Can you add a .zip file that can be used for integration testing to examples/nodejs/
? My local integration tests use https://github.com/tkeech1/kubelessfunction/blob/master/nodejs/helloFunctions.zip but I would like to update the tests to download the zip file from the kubeless repo to avoid creating a dependency on my repo. Thanks.
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.
It's okay to have it there for the moment, just upload the file with this PR. We can modify the URL after this PR gets merged.
Let's track that in a different Issue/PR. Also, we need to support URLs for the flag |
Hi @andresmgot, |
* pv for kafka * Update README.md Fix some typos and links
* <script/binary>: print more information when building * Update binary Fix typo
* Add response object to function event * Add docs
* CircleCI integration * Fix builder image ref * Remove debug code * Minor review * Store artifacts
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.
This is great, thank you for working on this! I just made a few minor comments now.
It also seems that you need to update the unit tests in function_test.go
. Once you fix that and apply the changes we can merge this PR.
Also can you update the docs at docs/advanced-function-deployment.md
? There is a small description of the supported content types.
cmd/kubeless/function/function.go
Outdated
} | ||
function.Spec.FunctionContentType = "url" | ||
// strip any query params to determine if the file is a zip | ||
if path.Ext(strings.Split(functionURL.String(), "?")[0]) == ".zip" { |
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 would move the check if strings.Index(file, "http://")
and if path.Ext(strings.Split(functionURL.String(), "?")[0]) == ".zip"
to the function getContentType
of the function.go
file so the same function always returns the full contentType
cmd/kubeless/function/function.go
Outdated
} else { | ||
function.Spec.Function = base64.StdEncoding.EncodeToString(functionBytes) | ||
} | ||
function.Spec.Checksum, err = getFileSha256(file) |
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 would create another function here that given a content type it returns the content and its checksum:
func parseContent(content, type) (string, string, error)
that function would read a file in case the type is text
do the base64
in case it is a zip or download the file in case it is an URL. That way you can reuse it for the dependencies file.
pkg/utils/k8sutil_test.go
Outdated
if !strings.HasPrefix(c.Args[0], "curl https://raw.githubusercontent.com/test/test/test/test.py --silent --output /tmp/func.fromurl") { | ||
t.Errorf("Unexpected command: %s", c.Args[0]) | ||
} | ||
|
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.
It's okay to have it there for the moment, just upload the file with this PR. We can modify the URL after this PR gets merged.
examples/Makefile
Outdated
get-python-url-deps: | ||
kubeless function deploy get-python-url-deps --runtime python2.7 --handler helloget.foo --from-file https://raw.githubusercontent.com/kubeless/kubeless/v1.0.0-alpha.1/examples/python/hellowithdeps.py --dependencies https://raw.githubusercontent.com/kubeless/kubeless/v1.0.0-alpha.1/examples/python/requirements.txt | ||
|
||
get-python-url-deps-verify: |
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.
This is very complete but these kind of tests take a long time to be executed in the CI. Can you merge get-python-url
, get-python-url-filedep
and get-python-url-deps
in just one test? Basically having just get-python-url-deps
since that one covers the previous two.
Thank you for addressing all the comments! We can merge this now. |
Issue Ref: Issue 705
Description:
This PR adds support for URLs in the --from-file command line flag which allows the user to specify a a raw code file or zip file when calling
function deploy
orfunction update
. For example:function deploy foo --runtime python2.7 --from-file https://raw.githubusercontent.com/<USER>/<REPO>/<BRANCH>/<FILE> --handler test.foobar
Thanks.
TODOs: