Merge pull request #107 from openziti/release-0.14.7

Add identity service config CLI commands. Add update terminator CLI c…
This commit is contained in:
Paul Lorenz
2020-06-01 14:58:48 -04:00
committed by GitHub
8 changed files with 291 additions and 31 deletions
+9
View File
@@ -1,3 +1,12 @@
# Release 0.14.7
## Theme
Ziti 0.14.7 includes the following:
* [Add CLI support for updating terminators](https://github.com/openziti/ziti/issues/106)
* [Add CLI support for managing identity service config overrides](https://github.com/openziti/ziti/issues/105)
NOTE: 0.14.6 was released with the same code as 0.14.5 due to CI re-running
# Release 0.14.5
## Theme
Ziti 0.14.5 includes the following:
+7 -2
View File
@@ -20,6 +20,7 @@ import (
"fmt"
"github.com/google/uuid"
"github.com/pkg/errors"
"os"
"strings"
)
@@ -48,7 +49,9 @@ func mapNameToID(entityType string, val string) (string, error) {
entity := list[0]
entityId, _ := entity.Path("id").Data().(string)
fmt.Printf("Found %v with id %v for name %v\n", entityType, entityId, val)
if val, found := os.LookupEnv("ZITI_CLI_DEBUG"); found && strings.EqualFold("true", val) {
fmt.Printf("Found %v with id %v for name %v\n", entityType, entityId, val)
}
return entityId, nil
}
@@ -86,7 +89,9 @@ func mapNamesToIDs(entityType string, list ...string) ([]string, error) {
for _, entity := range list {
entityId, _ := entity.Path("id").Data().(string)
result = append(result, entityId)
fmt.Printf("Found %v with id %v for name %v\n", entityType, entityId, val)
if val, found := os.LookupEnv("ZITI_CLI_DEBUG"); found && strings.EqualFold("true", val) {
fmt.Printf("Found %v with id %v for name %v\n", entityType, entityId, val)
}
}
}
}
@@ -19,10 +19,10 @@ package edge_controller
import (
"fmt"
"github.com/Jeffail/gabs"
"github.com/openziti/foundation/util/stringz"
"github.com/openziti/ziti/ziti/cmd/ziti/cmd/common"
cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory"
cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers"
"github.com/openziti/foundation/util/stringz"
"github.com/spf13/cobra"
"io"
"math"
@@ -33,7 +33,6 @@ type createTerminatorOptions struct {
binding string
cost int32
precedence string
tags map[string]string
}
// newCreateTerminatorCmd creates the 'edge controller create Terminator local' command for the given entity type
@@ -46,7 +45,6 @@ func newCreateTerminatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer)
Err: errOut,
},
},
tags: make(map[string]string),
}
cmd := &cobra.Command{
@@ -65,11 +63,10 @@ func newCreateTerminatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer)
// allow interspersing positional args and flags
cmd.Flags().SetInterspersed(true)
cmd.Flags().StringToStringVarP(&options.tags, "tags", "t", nil, "Add tags to terminator definition")
cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller")
cmd.Flags().StringVar(&options.binding, "binding", "transport", "Set the terminator binding")
cmd.Flags().Int32VarP(&options.cost, "cost", "c", -1, "Set the terminator cost")
cmd.Flags().StringVarP(&options.precedence, "precedence", "p", "", "Set the terminator precedence ('default', 'required' or 'failed'")
cmd.Flags().Int32VarP(&options.cost, "cost", "c", 0, "Set the terminator cost")
cmd.Flags().StringVarP(&options.precedence, "precedence", "p", "", "Set the terminator precedence ('default', 'required' or 'failed')")
return cmd
}
@@ -91,7 +88,6 @@ func runCreateTerminator(o *createTerminatorOptions) (err error) {
setJSONValue(entityData, router, "router")
setJSONValue(entityData, o.binding, "binding")
setJSONValue(entityData, o.Args[2], "address")
setJSONValue(entityData, o.tags, "tags")
if o.cost > 0 {
if o.cost > math.MaxUint16 {
if _, err = fmt.Fprintf(o.Out, "Invalid cost %v. Must be positive number less than or equal to %v\n", o.cost, math.MaxUint16); err != nil {
+30 -5
View File
@@ -92,6 +92,7 @@ func newListCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comma
identityListRootCmd.AddCommand(newSubListCmdForEntityType("identities", "edge-routers", outputEdgeRouters, newOptions()))
identityListRootCmd.AddCommand(newSubListCmdForEntityType("identities", "service-policies", outputServicePolicies, newOptions()))
identityListRootCmd.AddCommand(newSubListCmdForEntityType("identities", "services", outputServices, newOptions()))
identityListRootCmd.AddCommand(newSubListCmdForEntityType("identities", "service-configs", outputServiceConfigs, newOptions()))
serviceListRootCmd := newEntityListRootCmd("service")
serviceListRootCmd.AddCommand(newSubListCmdForEntityType("services", "configs", outputConfigs, newOptions()))
@@ -180,7 +181,7 @@ func newListCmdForEntityType(entityType string, command listCommandRunner, optio
// newListServicesCmd creates the list command for the given entity type
func newListServicesCmd(options *commonOptions) *cobra.Command {
var asIdentity string
var configTypes string
var configTypes []string
var roleFilters []string
var roleSemantic string
@@ -203,7 +204,7 @@ func newListServicesCmd(options *commonOptions) *cobra.Command {
cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller")
cmd.Flags().StringVar(&asIdentity, "as-identity", "", "Allow admins to see services as they would be seen by a different identity")
cmd.Flags().StringVar(&configTypes, "config-types", "", "Override which config types to view on services")
cmd.Flags().StringSliceVar(&configTypes, "config-types", nil, "Override which config types to view on services")
cmd.Flags().StringSliceVar(&roleFilters, "role-filters", nil, "Allow filtering by roles")
cmd.Flags().StringVar(&roleSemantic, "role-semantic", "", "Specify which roles semantic to use ")
@@ -467,7 +468,7 @@ func outputTerminators(o *commonOptions, children []*gabs.Container, pagingInfo
return nil
}
func runListServices(asIdentity string, configTypes string, roleFilters []string, roleSemantic string, options *commonOptions) error {
func runListServices(asIdentity string, configTypes []string, roleFilters []string, roleSemantic string, options *commonOptions) error {
params := url.Values{}
if len(options.Args) > 0 {
params.Add("filter", options.Args[0])
@@ -475,8 +476,13 @@ func runListServices(asIdentity string, configTypes string, roleFilters []string
if asIdentity != "" {
params.Add("asIdentity", asIdentity)
}
if configTypes != "" {
params.Add("configTypes", configTypes)
if configTypes, err := mapNamesToIDs("config-types", configTypes...); err != nil {
return err
} else {
for _, configType := range configTypes {
params.Add("configTypes", configType)
}
}
for _, roleFilter := range roleFilters {
params.Add("roleFilter", roleFilter)
@@ -510,6 +516,25 @@ func outputServices(o *commonOptions, children []*gabs.Container, pagingInfo *pa
return nil
}
func outputServiceConfigs(o *commonOptions, children []*gabs.Container, pagingInfo *paging) error {
if o.OutputJSONResponse {
return nil
}
for _, entity := range children {
service, _ := entity.Path("service").Data().(string)
serviceName, _ := mapIdToName("services", service)
config, _ := entity.Path("config").Data().(string)
configName, _ := mapIdToName("configs", config)
_, err := fmt.Fprintf(o.Out, "service: %v config: %v\n", serviceName, configName)
if err != nil {
return err
}
}
pagingInfo.output(o)
return nil
}
func runListServiceEdgeRouterPolices(o *commonOptions) error {
children, pagingInfo, err := listEntitiesWithOptions("service-edge-router-policies", o)
if err != nil {
+14 -4
View File
@@ -44,24 +44,34 @@ func newUpdateCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Com
cmd.AddCommand(newUpdateEdgeRouterCmd(f, out, errOut))
cmd.AddCommand(newUpdateEdgeRouterPolicyCmd(f, out, errOut))
cmd.AddCommand(newUpdateIdentityCmd(f, out, errOut))
cmd.AddCommand(newUpdateIdentityConfigsCmd(f, out, errOut))
cmd.AddCommand(newUpdateServiceCmd(f, out, errOut))
cmd.AddCommand(newUpdateServicePolicyCmd(f, out, errOut))
cmd.AddCommand(newUpdateServiceEdgeRouterPolicyCmd(f, out, errOut))
cmd.AddCommand(newUpdateTerminatorCmd(f, out, errOut))
return cmd
}
func putEntityOfType(entityType string, body string, options *commonOptions) (*gabs.Container, error) {
return updateEntityOfType(entityType, body, options, true)
return updateEntityOfType(entityType, body, options, resty.MethodPut)
}
func patchEntityOfType(entityType string, body string, options *commonOptions) (*gabs.Container, error) {
return updateEntityOfType(entityType, body, options, false)
return updateEntityOfType(entityType, body, options, resty.MethodPatch)
}
func postEntityOfType(entityType string, body string, options *commonOptions) (*gabs.Container, error) {
return updateEntityOfType(entityType, body, options, resty.MethodPost)
}
func deleteEntityOfTypeWithBody(entityType string, body string, options *commonOptions) (*gabs.Container, error) {
return updateEntityOfType(entityType, body, options, resty.MethodDelete)
}
// updateEntityOfType updates an entity of the given type on the Ziti Edge Controller
func updateEntityOfType(entityType string, body string, options *commonOptions, put bool) (*gabs.Container, error) {
return util.EdgeControllerUpdate(entityType, body, options.Out, put, options.OutputJSONResponse)
func updateEntityOfType(entityType string, body string, options *commonOptions, method string) (*gabs.Container, error) {
return util.EdgeControllerUpdate(entityType, body, options.Out, method, options.OutputJSONResponse)
}
func doRequest(entityType string, options *commonOptions, doRequest func(request *resty.Request, url string) (*resty.Response, error)) (*gabs.Container, error) {
@@ -0,0 +1,96 @@
/*
Copyright NetFoundry, Inc.
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
https://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 edge_controller
import (
"fmt"
"io"
"github.com/Jeffail/gabs"
"github.com/openziti/ziti/ziti/cmd/ziti/cmd/common"
cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory"
cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers"
"github.com/spf13/cobra"
)
type updateIdentityConfigsOptions struct {
commonOptions
remove bool
}
func newUpdateIdentityConfigsCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := &updateIdentityConfigsOptions{
commonOptions: commonOptions{
CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut},
},
}
cmd := &cobra.Command{
Use: "identity-configs <identity id or name> <service id or name> <config id or name>",
Short: "for the specified identity, use the given config for the given service",
Args: cobra.ExactArgs(3),
Run: func(cmd *cobra.Command, args []string) {
options.Cmd = cmd
options.Args = args
err := runupdateIdentityConfigs(options)
cmdhelper.CheckErr(err)
},
SuggestFor: []string{},
}
// allow interspersing positional args and flags
cmd.Flags().SetInterspersed(true)
cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller")
cmd.Flags().BoolVarP(&options.remove, "remove", "r", false, "Remove the sevice config override")
return cmd
}
// runupdateIdentityConfigs update a new identity on the Ziti Edge Controller
func runupdateIdentityConfigs(o *updateIdentityConfigsOptions) error {
id, err := mapNameToID("identities", o.Args[0])
if err != nil {
return err
}
serviceId, err := mapNameToID("services", o.Args[1])
if err != nil {
return err
}
configId, err := mapNameToID("configs", o.Args[2])
if err != nil {
return err
}
entityData, _ := gabs.New().ArrayOfSize(1)
serviceConfig := map[string]string{
"service": serviceId,
"config": configId,
}
_, _ = entityData.SetIndex(serviceConfig, 0)
path := fmt.Sprintf("identities/%v/service-configs", id)
body := entityData.String()
if o.remove {
_, err = deleteEntityOfTypeWithBody(path, body, &o.commonOptions)
} else {
_, err = postEntityOfType(path, body, &o.commonOptions)
}
return err
}
@@ -0,0 +1,126 @@
/*
Copyright NetFoundry, Inc.
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
https://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 edge_controller
import (
"errors"
"fmt"
"github.com/Jeffail/gabs"
"github.com/openziti/foundation/util/stringz"
"github.com/openziti/ziti/ziti/cmd/ziti/cmd/common"
cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory"
cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers"
errors2 "github.com/pkg/errors"
"github.com/spf13/cobra"
"io"
"math"
)
type updateTerminatorOptions struct {
commonOptions
router string
address string
binding string
cost int32
precedence string
}
func newUpdateTerminatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := &updateTerminatorOptions{
commonOptions: commonOptions{
CommonOptions: common.CommonOptions{
Factory: f,
Out: out,
Err: errOut,
},
},
}
cmd := &cobra.Command{
Use: "terminator <id>",
Short: "updates a service terminator",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
options.Cmd = cmd
options.Args = args
err := runUpdateTerminator(options)
cmdhelper.CheckErr(err)
},
SuggestFor: []string{},
}
// allow interspersing positional args and flags
cmd.Flags().SetInterspersed(true)
cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller")
cmd.Flags().StringVar(&options.router, "router", "", "Set the terminator router")
cmd.Flags().StringVar(&options.address, "address", "", "Set the terminator address")
cmd.Flags().StringVar(&options.binding, "binding", "", "Set the terminator binding")
cmd.Flags().Int32VarP(&options.cost, "cost", "c", 0, "Set the terminator cost")
cmd.Flags().StringVarP(&options.precedence, "precedence", "p", "", "Set the terminator precedence ('default', 'required' or 'failed')")
return cmd
}
// runUpdateTerminator implements the command to update a Terminator
func runUpdateTerminator(o *updateTerminatorOptions) (err error) {
entityData := gabs.New()
router, err := mapNameToID("edge-routers", o.router)
if err != nil {
router = o.router // might be a pure fabric router, id might not be UUID
}
change := false
if o.Cmd.Flags().Changed("router") {
setJSONValue(entityData, router, "router")
change = true
}
if o.Cmd.Flags().Changed("binding") {
setJSONValue(entityData, o.binding, "binding")
change = true
}
if o.Cmd.Flags().Changed("address") {
setJSONValue(entityData, o.address, "address")
change = true
}
if o.Cmd.Flags().Changed("cost") {
if o.cost > math.MaxUint16 {
return errors2.Errorf("Invalid cost %v. Must be positive number less than or equal to %v", o.cost, math.MaxUint16)
}
setJSONValue(entityData, o.cost, "cost")
change = true
}
if o.Cmd.Flags().Changed("precedence") {
validValues := []string{"default", "required", "failed"}
if !stringz.Contains(validValues, o.precedence) {
return errors2.Errorf("Invalid precedence %v. Must be one of %+v", o.precedence, validValues)
}
setJSONValue(entityData, o.precedence, "precedence")
change = true
}
if !change {
return errors.New("no change specified. must specify at least one attribute to change")
}
_, err = patchEntityOfType(fmt.Sprintf("terminators/%v", o.Args[0]), entityData.String(), &o.commonOptions)
return err
}
+6 -13
View File
@@ -24,10 +24,10 @@ import (
"fmt"
"github.com/Jeffail/gabs"
"github.com/blang/semver"
"github.com/openziti/foundation/common/constants"
"github.com/openziti/ziti/common/version"
cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers"
c "github.com/openziti/ziti/ziti/cmd/ziti/constants"
"github.com/openziti/foundation/common/constants"
"gopkg.in/resty.v1"
"io"
"net/http"
@@ -577,7 +577,7 @@ func EdgeControllerDelete(entityType string, id string, out io.Writer, logJSON b
}
// EdgeControllerUpdate will update entities of the given type in the given Edge Controller
func EdgeControllerUpdate(entityType string, body string, out io.Writer, put bool, logJSON bool) (*gabs.Container, error) {
func EdgeControllerUpdate(entityType string, body string, out io.Writer, method string, logJSON bool) (*gabs.Container, error) {
session := &Session{}
if err := session.Load(); err != nil {
return nil, err
@@ -589,26 +589,19 @@ func EdgeControllerUpdate(entityType string, body string, out io.Writer, put boo
client.SetRootCertificate(session.Cert)
}
request := client.
resp, err := client.
R().
SetHeader("Content-Type", "application/json").
SetHeader(constants.ZitiSession, session.Token).
SetBody(body)
var err error
var resp *resty.Response
if put {
resp, err = request.Put(session.Host + "/" + entityType)
} else {
resp, err = request.Patch(session.Host + "/" + entityType)
}
SetBody(body).
Execute(method, session.Host+"/"+entityType)
if err != nil {
return nil, fmt.Errorf("unable to update %v instance in Ziti Edge Controller at %v. Error: %v", entityType, session.Host, err)
}
if resp.StatusCode() != http.StatusOK {
return nil, fmt.Errorf("error creating %v instance in Ziti Edge Controller at %v. Status code: %v, Server returned: %v",
return nil, fmt.Errorf("error updating %v instance in Ziti Edge Controller at %v. Status code: %v, Server returned: %v",
entityType, session.Host, resp.Status(), resp.String())
}