-
Notifications
You must be signed in to change notification settings - Fork 10
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
Sample config file generation #43
Changes from 7 commits
1bfddb2
67a8397
55f63fc
237a6be
13018ed
8e7650e
5c7512b
7f2fcf0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Copyright 2020 Google LLC | ||
# | ||
# 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. | ||
|
||
# | ||
# If you change any templates: | ||
# 1. run this script to generate templates.go | ||
# 2. run `go mod tidy` to remove the go-bindata dep from your mod and sum files | ||
# 3. check in your changes | ||
# | ||
|
||
SCRIPTPATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
ROOTDIR="$(dirname "$SCRIPTPATH")" | ||
|
||
if [[ `command -v go-bindata` == "" ]]; then | ||
echo "go-bindata not installed, installing..." | ||
go get -u github.com/go-bindata/go-bindata/... | ||
fi | ||
|
||
TEMP_DIR=$(mktemp -d) | ||
TEMPLATES_SOURCE_DIR="${ROOTDIR}/templates" | ||
TEMPLATES_DIR="${TEMP_DIR}/templates" | ||
|
||
if [ ! -d "${TEMPLATES_DIR}" ]; then | ||
mkdir -p "${TEMPLATES_DIR}" | ||
fi | ||
|
||
|
||
cp -r "${TEMPLATES_SOURCE_DIR}/native" $TEMPLATES_DIR | ||
cp -r "${TEMPLATES_SOURCE_DIR}/istio-1.6" $TEMPLATES_DIR | ||
cp -r "${TEMPLATES_SOURCE_DIR}/istio-1.7" $TEMPLATES_DIR | ||
|
||
# create resource | ||
RESOURCE_FILE="${ROOTDIR}/templates/templates.go" | ||
echo "building ${RESOURCE_FILE}" | ||
cd ${TEMP_DIR} | ||
echo $(ls "${TEMP_DIR}/templates") | ||
go-bindata -nomemcopy -pkg "templates" -prefix "templates" -o "${RESOURCE_FILE}" templates/... | ||
|
||
echo "done" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
// Copyright 2020 Google LLC | ||
// | ||
// 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. | ||
|
||
package samples | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"net/url" | ||
"os" | ||
"path" | ||
"strings" | ||
"text/template" | ||
|
||
"github.com/apigee/apigee-remote-service-cli/cmd/provision" | ||
"github.com/apigee/apigee-remote-service-cli/shared" | ||
"github.com/apigee/apigee-remote-service-cli/templates" | ||
"github.com/apigee/apigee-remote-service-envoy/server" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
const ( | ||
nativeTemplateDir = "native" | ||
istioTemplateDir = "istio-1.6" | ||
) | ||
|
||
type samples struct { | ||
*shared.RootArgs | ||
isNative bool | ||
outDir string | ||
overwrite bool | ||
RuntimeHost string | ||
TargetService targetService | ||
TLS tls | ||
EncodedName string | ||
} | ||
|
||
type targetService struct { | ||
Name string | ||
Host string | ||
Prefix string | ||
} | ||
|
||
type tls struct { | ||
Dir string | ||
Key string | ||
Crt string | ||
} | ||
|
||
// Cmd returns base command | ||
func Cmd(rootArgs *shared.RootArgs, printf shared.FormatFn) *cobra.Command { | ||
s := &samples{ | ||
RootArgs: rootArgs, | ||
TargetService: targetService{}, | ||
TLS: tls{}, | ||
} | ||
|
||
c := &cobra.Command{ | ||
Use: "samples", | ||
Short: "Managing sample configuration files for remote-service deployment", | ||
Long: `Managing sample configuration files for remote-service deployment`, | ||
Args: cobra.NoArgs, | ||
} | ||
|
||
c.AddCommand(cmdCreateSampleConfig(s, printf)) | ||
|
||
return c | ||
} | ||
|
||
func cmdCreateSampleConfig(s *samples, printf shared.FormatFn) *cobra.Command { | ||
c := &cobra.Command{ | ||
Use: "create", | ||
Short: "Create sample configuration files for native envoy or istio", | ||
Long: `Create sample configuration files for native envoy or istio. A valid config | ||
yaml file generated through provisioning is required via --config/-c. Files will be in | ||
the directory specified via --out (default ./samples). | ||
In the case of native envoy, it takes the host of the target service, the desired name | ||
for its cluster and optionally the path prefix for matching. It also sets custom SSL | ||
connection from the envoy to the remote-service cluster if a folder containing tls.key | ||
and tls.crt is provided via --tls/-t. | ||
In the case of istio where envoy proxy acts as sidecars, if the target is unspecified, | ||
the httpbin example will be generated. Otherwise, users are responsible for preparing | ||
files related to deployment of their target services.`, | ||
Args: cobra.NoArgs, | ||
|
||
RunE: func(cmd *cobra.Command, _ []string) error { | ||
err := s.loadConfig() | ||
if err != nil { | ||
return errors.Wrap(err, "loading config yaml file") | ||
} | ||
return errors.Wrap(s.createSampleConfigs(printf), "creating sample config files") | ||
}, | ||
} | ||
|
||
c.Flags().StringVarP(&s.ConfigPath, "config", "c", "", "Path to Apigee Remote Service config file") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. de-capitalize - all the other descriptions start lowercase There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, the config file description in the root.go is identical to this. I am going to change both to lower case. |
||
c.Flags().BoolVarP(&s.isNative, "native", "", false, "generate config for native envoy (otherwise assuming istio)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder... could we pass a template name instead? So, for example, a user could pass in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. |
||
c.Flags().BoolVarP(&s.overwrite, "force", "f", false, "force overwriting existing directory") | ||
c.Flags().StringVarP(&s.outDir, "out", "", "./samples", "directory to create config files within") | ||
c.Flags().StringVarP(&s.TargetService.Name, "name", "n", "httpbin", "target service name") | ||
c.Flags().StringVarP(&s.TargetService.Host, "host", "", "httpbin.org", "target service host") | ||
c.Flags().StringVarP(&s.TargetService.Prefix, "prefix", "p", "/", "target service prefix") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should remove path rewrite because of the confusing issues around ordering. Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, but I already removed the prefix rewriting. This flag is taking the path for matching, i.e., for the Envoy router to take the request to the desired upstream cluster. Should we remove that as well? I think it probably should stay. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha. Hmm. But the only benefit would be to allow other endpoints to not be captured by the matcher, correct? Is that important for sample generation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true. All traffics are meant for the only target in the sample. Let me remove it then. |
||
c.Flags().StringVarP(&s.TLS.Dir, "tls", "t", "", "directory for tls key and crt") | ||
|
||
_ = c.MarkFlagRequired("config") | ||
|
||
return c | ||
} | ||
|
||
func (s *samples) loadConfig() error { | ||
s.ServerConfig = &server.Config{} | ||
err := s.ServerConfig.Load(s.ConfigPath, "") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
s.RuntimeBase = strings.Split(s.ServerConfig.Tenant.RemoteServiceAPI, "/remote-service")[0] | ||
url, err := url.Parse(s.RuntimeBase) | ||
if err != nil { | ||
return err | ||
} | ||
s.RuntimeHost = url.Hostname() | ||
s.Org = s.ServerConfig.Tenant.OrgName | ||
s.Env = s.ServerConfig.Tenant.EnvName | ||
s.Namespace = s.ServerConfig.Global.Namespace | ||
s.EncodedName = provision.EnvScopeEncodedName(s.Org, s.Env) | ||
|
||
if s.TLS.Dir != "" { | ||
s.TLS.Key = path.Join(s.TLS.Dir, "tls.key") | ||
s.TLS.Crt = path.Join(s.TLS.Dir, "tls.crt") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (s *samples) createSampleConfigs(printf shared.FormatFn) error { | ||
_, err := ioutil.ReadDir(s.outDir) | ||
if err != nil { | ||
if err := os.Mkdir(s.outDir, 0755); err != nil { | ||
return err | ||
} | ||
} else if s.overwrite { | ||
printf("overwriting the existing directory...") | ||
} else { | ||
return fmt.Errorf("output directory already exists") | ||
} | ||
if s.isNative { | ||
printf("generating the configuration file for native envoy proxy...") | ||
return s.createConfig(nativeTemplateDir, printf) | ||
} | ||
printf("generating configuration files envoy as sidecars...") | ||
return s.createConfig(istioTemplateDir, printf) | ||
} | ||
|
||
func (s *samples) createConfig(templateDir string, printf shared.FormatFn) error { | ||
tempDir, err := ioutil.TempDir("", "apigee") | ||
if err != nil { | ||
return errors.Wrap(err, "creating temp dir") | ||
} | ||
defer os.RemoveAll(tempDir) | ||
|
||
err = getTemplates(tempDir, templateDir) | ||
if err != nil { | ||
return errors.Wrap(err, "getting templates") | ||
} | ||
path := path.Join(tempDir, templateDir) | ||
templates, err := ioutil.ReadDir(path) | ||
if err != nil { | ||
return errors.Wrap(err, "getting templates directory") | ||
} | ||
for _, f := range templates { | ||
if f.Name() == "httpbin.yaml" && s.TargetService.Name != "httpbin" { | ||
continue | ||
} | ||
err := s.createConfigYaml(path, f.Name(), printf) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (s *samples) createConfigYaml(dir string, name string, printf shared.FormatFn) error { | ||
tmpl, err := template.New(name).ParseFiles(path.Join(dir, name)) | ||
if err != nil { | ||
return err | ||
} | ||
f, err := os.OpenFile(path.Join(s.outDir, name), os.O_WRONLY|os.O_CREATE, 0755) | ||
if err != nil { | ||
return err | ||
} | ||
printf("generating %s...", name) | ||
return tmpl.Execute(f, s) | ||
} | ||
|
||
// getTemplates unzips the templates to the tempDir/templates and returns the directory | ||
func getTemplates(tempDir string, name string) error { | ||
if err := templates.RestoreAssets(tempDir, name); err != nil { | ||
return errors.Wrapf(err, "restoring asset %s", name) | ||
} | ||
return nil | ||
} |
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 should emit a final message when it finishes successfully. Maybe remind them of the next steps: label the default namespace and run kubectl apply on the directory?
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.
Sure.