Skip to content
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

Pull templates from store when not present #1004

Merged
merged 9 commits into from
Jan 23, 2025
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,9 @@ Find templates with: `faas-cli template store list`

> Note: You can set your own custom store location with `--url` flag or set `OPENFAAS_TEMPLATE_STORE_URL` environmental variable

To pull templates from the store just write the name of the template you want `faas-cli template store pull go` or the repository and name `faas-cli template store pull openfaas/go`
To pull templates from the store just write the name of the template you want `faas-cli template store pull golang-middleware` or the repository and name `faas-cli template store pull openfaas/golang-middleware`

To get more detail on a template just use the `template store describe` command and pick a template of your choice, example with `go` would look like this `faas-cli template store describe go`
To get more detail on a template just use the `template store describe` command and pick a template of your choice, example with `go` would look like this `faas-cli template store describe golang-middleware`

> Note: This feature is still in experimental stage and in the future the CLI verbs might be changed

Expand Down
30 changes: 23 additions & 7 deletions build_integration_test.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#!/bin/bash

set -e # Exit script immediately on first error.
set -x # Print commands and their arguments as they are executed.
set -o pipefail # Print commands and their arguments as they are

cli="./bin/faas-cli"
template="python3"

TEMPLATE_NAME="python3-http"

get_package() {
uname=$(uname)
Expand All @@ -22,26 +27,30 @@ get_package() {
case $arch in
"armv6l" | "armv7l")
cli="./faas-cli-armhf"
template="python3-armhf"
;;
esac
;;
esac

echo "Using package $cli"
echo "Using template $template"
echo "Using template $TEMPLATE_NAME"
}

build_faas_function() {

function_name=$1

eval $cli new $function_name --lang $template
eval $cli new $function_name --lang $TEMPLATE_NAME

cat << EOF > $function_name/handler.py
def handle(req):

return "Function output from integration testing: Hello World!"
def handle(event, context):
return {
"statusCode": 200,
"body": {"message": "Hello from OpenFaaS!"},
"headers": {
"Content-Type": "application/json"
}
}
EOF

eval $cli build -f $function_name.yml
Expand Down Expand Up @@ -120,6 +129,13 @@ EOF
rm -rf got.txt want.txt $function_name*
}

get_templates() {
echo "Getting templates..."
eval $cli template store pull $TEMPLATE_NAME
}

get_templates

get_package
build_faas_function $FUNCTION
run_and_test $FUNCTION $PORT $FUNCTION_UP_TIMEOUT
Expand Down
2 changes: 1 addition & 1 deletion builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func BuildImage(image string, handler string, functionName string, language stri

if stack.IsValidTemplate(language) {
pathToTemplateYAML := fmt.Sprintf("./template/%s/template.yml", language)
if _, err := os.Stat(pathToTemplateYAML); os.IsNotExist(err) {
if _, err := os.Stat(pathToTemplateYAML); err != nil && os.IsNotExist(err) {
return err
}

Expand Down
2 changes: 1 addition & 1 deletion builder/copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func checkDestinationFiles(dir string, numberOfFiles, mode int) error {
// Check each file inside the destination folder
for i := 1; i <= numberOfFiles; i++ {
fileStat, err := os.Stat(fmt.Sprintf("%s/test-file-%d", dir, i))
if os.IsNotExist(err) {
if err != nil && os.IsNotExist(err) {
return err
}
if fileStat.Mode() != os.FileMode(mode) {
Expand Down
2 changes: 1 addition & 1 deletion builder/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func PublishImage(image string, handler string, functionName string, language st

if stack.IsValidTemplate(language) {
pathToTemplateYAML := fmt.Sprintf("./template/%s/template.yml", language)
if _, err := os.Stat(pathToTemplateYAML); os.IsNotExist(err) {
if _, err := os.Stat(pathToTemplateYAML); err != nil && os.IsNotExist(err) {
return err
}

Expand Down
34 changes: 20 additions & 14 deletions commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package commands

import (
"fmt"
"log"
"os"
"strings"
"sync"
Expand Down Expand Up @@ -155,6 +154,8 @@ func parseBuildArgs(args []string) (map[string]string, error) {

func runBuild(cmd *cobra.Command, args []string) error {

templateName := "" // templateName may not be known at this point

var services stack.Services
if len(yamlFile) > 0 {
parsedServices, err := stack.ParseYAMLFile(yamlFile, regex, filter, envsubst)
Expand All @@ -178,8 +179,8 @@ func runBuild(cmd *cobra.Command, args []string) error {
}
} else {
templateAddress := getTemplateURL("", os.Getenv(templateURLEnvironment), DefaultTemplateRepository)
if pullErr := pullTemplates(templateAddress); pullErr != nil {
return fmt.Errorf("could not pull templates for OpenFaaS: %v", pullErr)
if err := pullTemplates(templateAddress, templateName); err != nil {
return fmt.Errorf("could not pull templates: %v", err)
}
}

Expand Down Expand Up @@ -304,20 +305,25 @@ func build(services *stack.Services, queueDepth int, shrinkwrap, quietBuild bool
}

// pullTemplates pulls templates from specified git remote. templateURL may be a pinned repository.
func pullTemplates(templateURL string) error {
var err error
exists, err := os.Stat("./template")
if err != nil || exists == nil {
log.Println("No templates found in current directory.")

templateURL, refName := versioncontrol.ParsePinnedRemote(templateURL)
err = fetchTemplates(templateURL, refName, false)
if err != nil {
log.Println("Unable to download templates from Github.")
func pullTemplates(templateURL, templateName string) error {

if _, err := os.Stat("./template"); err != nil {
if os.IsNotExist(err) {

fmt.Printf("No templates found in current directory.\n")

templateURL, refName := versioncontrol.ParsePinnedRemote(templateURL)
if err := fetchTemplates(templateURL, refName, templateName, false); err != nil {
return err
}
} else {

// Perhaps there was a permissions issue or something else.
return err
}
}
return err

return nil
}

func combineBuildOpts(YAMLBuildOpts []string, buildFlagBuildOpts []string) []string {
Expand Down
2 changes: 1 addition & 1 deletion commands/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ func deriveFprocess(function stack.Function) (string, error) {
}

pathToTemplateYAML := "./template/" + function.Language + "/template.yml"
if _, err := os.Stat(pathToTemplateYAML); os.IsNotExist(err) {
if _, err := os.Stat(pathToTemplateYAML); err != nil && os.IsNotExist(err) {
return "", err
}

Expand Down
10 changes: 7 additions & 3 deletions commands/faas.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import (
)

const (
defaultGateway = "http://127.0.0.1:8080"
defaultNetwork = ""
defaultYAML = "stack.yml"
defaultGateway = "http://127.0.0.1:8080"
defaultNetwork = ""
defaultYML = "stack.yml"
defaultYAML = "stack.yaml"

defaultSchemaVersion = "1.0"
)

Expand Down Expand Up @@ -144,6 +146,8 @@ func checkAndSetDefaultYaml() {
// Check if there is a default yaml file and set it
if _, err := stat(defaultYAML); err == nil {
yamlFile = defaultYAML
} else if _, err := stat(defaultYML); err == nil {
yamlFile = defaultYML
}
}

Expand Down
6 changes: 3 additions & 3 deletions commands/faas_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package commands

import (
"io/ioutil"
"io"
"os"
"testing"
)
Expand All @@ -11,15 +11,15 @@ var mockStatParams string
func setupFaas(statError error) {
yamlFile = ""
mockStatParams = ""
faasCmd.SetOutput(ioutil.Discard)
faasCmd.SetOutput(io.Discard)

stat = func(f string) (os.FileInfo, error) {
mockStatParams = f
return nil, statError
}
}

func TestCallsStatWithDefaulYAMLFileName(t *testing.T) {
func TestCallsStatWithDefaultYAMLFileName(t *testing.T) {
setupFaas(nil)

Execute([]string{"help"})
Expand Down
60 changes: 38 additions & 22 deletions commands/fetch_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package commands

import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
Expand All @@ -20,21 +19,22 @@ const DefaultTemplateRepository = "https://github.com/openfaas/templates.git"
const templateDirectory = "./template/"

// fetchTemplates fetch code templates using git clone.
func fetchTemplates(templateURL string, refName string, overwrite bool) error {
func fetchTemplates(templateURL, refName, templateName string, overwrite bool) error {
if len(templateURL) == 0 {
return fmt.Errorf("pass valid templateURL")
}

dir, err := os.MkdirTemp("", "openfaas-templates-*")
if err != nil {
log.Fatal(err)
return err
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to return an error than use Fatal

}

if !pullDebug {
defer os.RemoveAll(dir) // clean up
defer os.RemoveAll(dir)
}

log.Printf("Attempting to expand templates from %s\n", templateURL)
pullDebugPrint(fmt.Sprintf("Temp files in %s", dir))

args := map[string]string{"dir": dir, "repo": templateURL}
cmd := versioncontrol.GitCloneDefault

Expand All @@ -47,7 +47,7 @@ func fetchTemplates(templateURL string, refName string, overwrite bool) error {
return err
}

preExistingLanguages, fetchedLanguages, err := moveTemplates(dir, overwrite)
preExistingLanguages, fetchedLanguages, err := moveTemplates(dir, templateName, overwrite)
if err != nil {
return err
}
Expand All @@ -56,7 +56,7 @@ func fetchTemplates(templateURL string, refName string, overwrite bool) error {
log.Printf("Cannot overwrite the following %d template(s): %v\n", len(preExistingLanguages), preExistingLanguages)
}

log.Printf("Fetched %d template(s) : %v from %s\n", len(fetchedLanguages), fetchedLanguages, templateURL)
fmt.Printf("Wrote %d template(s) : %v from %s\n", len(fetchedLanguages), fetchedLanguages, templateURL)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to be using "log" package here in the CLI output


return err
}
Expand Down Expand Up @@ -87,7 +87,7 @@ func templateFolderExists(language string, overwrite bool) bool {
return true
}

func moveTemplates(repoPath string, overwrite bool) ([]string, []string, error) {
func moveTemplates(repoPath, templateName string, overwrite bool) ([]string, []string, error) {
var (
existingLanguages []string
fetchedLanguages []string
Expand All @@ -97,7 +97,7 @@ func moveTemplates(repoPath string, overwrite bool) ([]string, []string, error)
availableLanguages := make(map[string]bool)

templateDir := filepath.Join(repoPath, templateDirectory)
templates, err := ioutil.ReadDir(templateDir)
templates, err := os.ReadDir(templateDir)
if err != nil {
return nil, nil, fmt.Errorf("can't find templates in: %s", repoPath)
}
Expand All @@ -108,23 +108,35 @@ func moveTemplates(repoPath string, overwrite bool) ([]string, []string, error)
}
language := file.Name()

canWrite := canWriteLanguage(availableLanguages, language, overwrite)
if canWrite {
fetchedLanguages = append(fetchedLanguages, language)
// Do cp here
languageSrc := filepath.Join(templateDir, language)
languageDest := filepath.Join(templateDirectory, language)
builder.CopyFiles(languageSrc, languageDest)
} else {
existingLanguages = append(existingLanguages, language)
continue
if len(templateName) == 0 {

canWrite := canWriteLanguage(availableLanguages, language, overwrite)
if canWrite {
fetchedLanguages = append(fetchedLanguages, language)
// Do cp here
languageSrc := filepath.Join(templateDir, language)
languageDest := filepath.Join(templateDirectory, language)
builder.CopyFiles(languageSrc, languageDest)
} else {
existingLanguages = append(existingLanguages, language)
continue
}
} else if language == templateName {

if canWriteLanguage(availableLanguages, language, overwrite) {
fetchedLanguages = append(fetchedLanguages, language)
// Do cp here
languageSrc := filepath.Join(templateDir, language)
languageDest := filepath.Join(templateDirectory, language)
builder.CopyFiles(languageSrc, languageDest)
}
}
}

return existingLanguages, fetchedLanguages, nil
}

func pullTemplate(repository string) error {
func pullTemplate(repository, templateName string) error {
if _, err := os.Stat(repository); err != nil {
if !versioncontrol.IsGitRemote(repository) && !versioncontrol.IsPinnedGitRemote(repository) {
return fmt.Errorf("the repository URL must be a valid git repo uri")
Expand All @@ -143,8 +155,12 @@ func pullTemplate(repository string) error {
}
}

fmt.Printf("Fetch templates from repository: %s at %s\n", repository, refName)
if err := fetchTemplates(repository, refName, overwrite); err != nil {
refStr := ""
if len(refName) > 0 {
refStr = fmt.Sprintf(" @ %s", refName)
}
fmt.Printf("Fetch templates from repository: %s%s\n", repository, refStr)
if err := fetchTemplates(repository, refName, templateName, overwrite); err != nil {
return fmt.Errorf("error while fetching templates: %s", err)
}

Expand Down
11 changes: 6 additions & 5 deletions commands/fetch_templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ func Test_PullTemplates(t *testing.T) {
defer os.RemoveAll(localTemplateRepository)
defer tearDownFetchTemplates(t)

templateName := ""
t.Run("pullTemplates", func(t *testing.T) {
defer tearDownFetchTemplates(t)
if err := pullTemplates(localTemplateRepository); err != nil {
t.Fatal(err)
if err := pullTemplates(localTemplateRepository, templateName); err != nil {
t.Fatalf("Trying to pull %s, error: %s", localTemplateRepository, err)
}
})

t.Run("fetchTemplates with master ref", func(t *testing.T) {
defer tearDownFetchTemplates(t)

if err := fetchTemplates(localTemplateRepository, "master", false); err != nil {
if err := fetchTemplates(localTemplateRepository, "master", templateName, false); err != nil {
t.Fatal(err)
}

Expand All @@ -40,8 +41,8 @@ func Test_PullTemplates(t *testing.T) {
t.Run("fetchTemplates with default ref", func(t *testing.T) {
defer tearDownFetchTemplates(t)

err := fetchTemplates(localTemplateRepository, "", false)
if err != nil {
templateName := ""
if err := fetchTemplates(localTemplateRepository, "", templateName, false); err != nil {
t.Error(err)
}

Expand Down
Loading
Loading