mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-21 00:06:37 +00:00
**What** - Use the compose-go library to read the service definitions from an external compose file instead of building them in Go - Add default compose file and copy during `faasd install` - Add test for load and parse of compose file - Make testing easier by sorting the env keys - Allow append to instantiate the slices so that we can more easily test for proper parsing (e.g. nil is still nil etc) - Add the arch suffix to the compose file and set this as part of the env when we parse the compose file. This allows faasd to dynamically set the arch suffix used for the basic auth and the gateway images. Signed-off-by: Lucas Roesler <roesler.lucas@gmail.com>
387 lines
9.5 KiB
Go
Generated
387 lines
9.5 KiB
Go
Generated
// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// author xeipuuv
|
|
// author-github https://github.com/xeipuuv
|
|
// author-mail xeipuuv@gmail.com
|
|
//
|
|
// repository-name gojsonschema
|
|
// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
|
|
//
|
|
// description Different strategies to load JSON files.
|
|
// Includes References (file and HTTP), JSON strings and Go types.
|
|
//
|
|
// created 01-02-2015
|
|
|
|
package gojsonschema
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/xeipuuv/gojsonreference"
|
|
)
|
|
|
|
var osFS = osFileSystem(os.Open)
|
|
|
|
// JSONLoader defines the JSON loader interface
|
|
type JSONLoader interface {
|
|
JsonSource() interface{}
|
|
LoadJSON() (interface{}, error)
|
|
JsonReference() (gojsonreference.JsonReference, error)
|
|
LoaderFactory() JSONLoaderFactory
|
|
}
|
|
|
|
// JSONLoaderFactory defines the JSON loader factory interface
|
|
type JSONLoaderFactory interface {
|
|
// New creates a new JSON loader for the given source
|
|
New(source string) JSONLoader
|
|
}
|
|
|
|
// DefaultJSONLoaderFactory is the default JSON loader factory
|
|
type DefaultJSONLoaderFactory struct {
|
|
}
|
|
|
|
// FileSystemJSONLoaderFactory is a JSON loader factory that uses http.FileSystem
|
|
type FileSystemJSONLoaderFactory struct {
|
|
fs http.FileSystem
|
|
}
|
|
|
|
// New creates a new JSON loader for the given source
|
|
func (d DefaultJSONLoaderFactory) New(source string) JSONLoader {
|
|
return &jsonReferenceLoader{
|
|
fs: osFS,
|
|
source: source,
|
|
}
|
|
}
|
|
|
|
// New creates a new JSON loader for the given source
|
|
func (f FileSystemJSONLoaderFactory) New(source string) JSONLoader {
|
|
return &jsonReferenceLoader{
|
|
fs: f.fs,
|
|
source: source,
|
|
}
|
|
}
|
|
|
|
// osFileSystem is a functional wrapper for os.Open that implements http.FileSystem.
|
|
type osFileSystem func(string) (*os.File, error)
|
|
|
|
// Opens a file with the given name
|
|
func (o osFileSystem) Open(name string) (http.File, error) {
|
|
return o(name)
|
|
}
|
|
|
|
// JSON Reference loader
|
|
// references are used to load JSONs from files and HTTP
|
|
|
|
type jsonReferenceLoader struct {
|
|
fs http.FileSystem
|
|
source string
|
|
}
|
|
|
|
func (l *jsonReferenceLoader) JsonSource() interface{} {
|
|
return l.source
|
|
}
|
|
|
|
func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
|
return gojsonreference.NewJsonReference(l.JsonSource().(string))
|
|
}
|
|
|
|
func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory {
|
|
return &FileSystemJSONLoaderFactory{
|
|
fs: l.fs,
|
|
}
|
|
}
|
|
|
|
// NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system.
|
|
func NewReferenceLoader(source string) JSONLoader {
|
|
return &jsonReferenceLoader{
|
|
fs: osFS,
|
|
source: source,
|
|
}
|
|
}
|
|
|
|
// NewReferenceLoaderFileSystem returns a JSON reference loader using the given source and file system.
|
|
func NewReferenceLoaderFileSystem(source string, fs http.FileSystem) JSONLoader {
|
|
return &jsonReferenceLoader{
|
|
fs: fs,
|
|
source: source,
|
|
}
|
|
}
|
|
|
|
func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
|
|
|
|
var err error
|
|
|
|
reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
refToURL := reference
|
|
refToURL.GetUrl().Fragment = ""
|
|
|
|
var document interface{}
|
|
|
|
if reference.HasFileScheme {
|
|
|
|
filename := strings.TrimPrefix(refToURL.String(), "file://")
|
|
filename, err = url.QueryUnescape(filename)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if runtime.GOOS == "windows" {
|
|
// on Windows, a file URL may have an extra leading slash, use slashes
|
|
// instead of backslashes, and have spaces escaped
|
|
filename = strings.TrimPrefix(filename, "/")
|
|
filename = filepath.FromSlash(filename)
|
|
}
|
|
|
|
document, err = l.loadFromFile(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
} else {
|
|
|
|
document, err = l.loadFromHTTP(refToURL.String())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
}
|
|
|
|
return document, nil
|
|
|
|
}
|
|
|
|
func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) {
|
|
|
|
// returned cached versions for metaschemas for drafts 4, 6 and 7
|
|
// for performance and allow for easier offline use
|
|
if metaSchema := drafts.GetMetaSchema(address); metaSchema != "" {
|
|
return decodeJSONUsingNumber(strings.NewReader(metaSchema))
|
|
}
|
|
|
|
resp, err := http.Get(address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// must return HTTP Status 200 OK
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, errors.New(formatErrorDescription(Locale.HttpBadStatus(), ErrorDetails{"status": resp.Status}))
|
|
}
|
|
|
|
bodyBuff, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return decodeJSONUsingNumber(bytes.NewReader(bodyBuff))
|
|
}
|
|
|
|
func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) {
|
|
f, err := l.fs.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
bodyBuff, err := ioutil.ReadAll(f)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return decodeJSONUsingNumber(bytes.NewReader(bodyBuff))
|
|
|
|
}
|
|
|
|
// JSON string loader
|
|
|
|
type jsonStringLoader struct {
|
|
source string
|
|
}
|
|
|
|
func (l *jsonStringLoader) JsonSource() interface{} {
|
|
return l.source
|
|
}
|
|
|
|
func (l *jsonStringLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
|
return gojsonreference.NewJsonReference("#")
|
|
}
|
|
|
|
func (l *jsonStringLoader) LoaderFactory() JSONLoaderFactory {
|
|
return &DefaultJSONLoaderFactory{}
|
|
}
|
|
|
|
// NewStringLoader creates a new JSONLoader, taking a string as source
|
|
func NewStringLoader(source string) JSONLoader {
|
|
return &jsonStringLoader{source: source}
|
|
}
|
|
|
|
func (l *jsonStringLoader) LoadJSON() (interface{}, error) {
|
|
|
|
return decodeJSONUsingNumber(strings.NewReader(l.JsonSource().(string)))
|
|
|
|
}
|
|
|
|
// JSON bytes loader
|
|
|
|
type jsonBytesLoader struct {
|
|
source []byte
|
|
}
|
|
|
|
func (l *jsonBytesLoader) JsonSource() interface{} {
|
|
return l.source
|
|
}
|
|
|
|
func (l *jsonBytesLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
|
return gojsonreference.NewJsonReference("#")
|
|
}
|
|
|
|
func (l *jsonBytesLoader) LoaderFactory() JSONLoaderFactory {
|
|
return &DefaultJSONLoaderFactory{}
|
|
}
|
|
|
|
// NewBytesLoader creates a new JSONLoader, taking a `[]byte` as source
|
|
func NewBytesLoader(source []byte) JSONLoader {
|
|
return &jsonBytesLoader{source: source}
|
|
}
|
|
|
|
func (l *jsonBytesLoader) LoadJSON() (interface{}, error) {
|
|
return decodeJSONUsingNumber(bytes.NewReader(l.JsonSource().([]byte)))
|
|
}
|
|
|
|
// JSON Go (types) loader
|
|
// used to load JSONs from the code as maps, interface{}, structs ...
|
|
|
|
type jsonGoLoader struct {
|
|
source interface{}
|
|
}
|
|
|
|
func (l *jsonGoLoader) JsonSource() interface{} {
|
|
return l.source
|
|
}
|
|
|
|
func (l *jsonGoLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
|
return gojsonreference.NewJsonReference("#")
|
|
}
|
|
|
|
func (l *jsonGoLoader) LoaderFactory() JSONLoaderFactory {
|
|
return &DefaultJSONLoaderFactory{}
|
|
}
|
|
|
|
// NewGoLoader creates a new JSONLoader from a given Go struct
|
|
func NewGoLoader(source interface{}) JSONLoader {
|
|
return &jsonGoLoader{source: source}
|
|
}
|
|
|
|
func (l *jsonGoLoader) LoadJSON() (interface{}, error) {
|
|
|
|
// convert it to a compliant JSON first to avoid types "mismatches"
|
|
|
|
jsonBytes, err := json.Marshal(l.JsonSource())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return decodeJSONUsingNumber(bytes.NewReader(jsonBytes))
|
|
|
|
}
|
|
|
|
type jsonIOLoader struct {
|
|
buf *bytes.Buffer
|
|
}
|
|
|
|
// NewReaderLoader creates a new JSON loader using the provided io.Reader
|
|
func NewReaderLoader(source io.Reader) (JSONLoader, io.Reader) {
|
|
buf := &bytes.Buffer{}
|
|
return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf)
|
|
}
|
|
|
|
// NewWriterLoader creates a new JSON loader using the provided io.Writer
|
|
func NewWriterLoader(source io.Writer) (JSONLoader, io.Writer) {
|
|
buf := &bytes.Buffer{}
|
|
return &jsonIOLoader{buf: buf}, io.MultiWriter(source, buf)
|
|
}
|
|
|
|
func (l *jsonIOLoader) JsonSource() interface{} {
|
|
return l.buf.String()
|
|
}
|
|
|
|
func (l *jsonIOLoader) LoadJSON() (interface{}, error) {
|
|
return decodeJSONUsingNumber(l.buf)
|
|
}
|
|
|
|
func (l *jsonIOLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
|
return gojsonreference.NewJsonReference("#")
|
|
}
|
|
|
|
func (l *jsonIOLoader) LoaderFactory() JSONLoaderFactory {
|
|
return &DefaultJSONLoaderFactory{}
|
|
}
|
|
|
|
// JSON raw loader
|
|
// In case the JSON is already marshalled to interface{} use this loader
|
|
// This is used for testing as otherwise there is no guarantee the JSON is marshalled
|
|
// "properly" by using https://golang.org/pkg/encoding/json/#Decoder.UseNumber
|
|
type jsonRawLoader struct {
|
|
source interface{}
|
|
}
|
|
|
|
// NewRawLoader creates a new JSON raw loader for the given source
|
|
func NewRawLoader(source interface{}) JSONLoader {
|
|
return &jsonRawLoader{source: source}
|
|
}
|
|
func (l *jsonRawLoader) JsonSource() interface{} {
|
|
return l.source
|
|
}
|
|
func (l *jsonRawLoader) LoadJSON() (interface{}, error) {
|
|
return l.source, nil
|
|
}
|
|
func (l *jsonRawLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
|
return gojsonreference.NewJsonReference("#")
|
|
}
|
|
func (l *jsonRawLoader) LoaderFactory() JSONLoaderFactory {
|
|
return &DefaultJSONLoaderFactory{}
|
|
}
|
|
|
|
func decodeJSONUsingNumber(r io.Reader) (interface{}, error) {
|
|
|
|
var document interface{}
|
|
|
|
decoder := json.NewDecoder(r)
|
|
decoder.UseNumber()
|
|
|
|
err := decoder.Decode(&document)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return document, nil
|
|
|
|
}
|