diff --git a/common/version/VERSION b/common/version/VERSION index ee6cdce3c..faef31a43 100644 --- a/common/version/VERSION +++ b/common/version/VERSION @@ -1 +1 @@ -0.6.1 +0.7.0 diff --git a/go.mod b/go.mod index eb72cb61f..ef5f3ca1d 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,11 @@ module github.com/netfoundry/ziti-cmd go 1.13 +// replace github.com/netfoundry/ziti-foundation => ../ziti-foundation +// replace github.com/netfoundry/ziti-fabric => ../ziti-fabric +//replace github.com/netfoundry/ziti-sdk-golang => ../ziti-sdk-golang +// replace github.com/netfoundry/ziti-edge => ../ziti-edge + require ( github.com/Jeffail/gabs v1.4.0 github.com/MakeNowJust/heredoc v1.0.0 @@ -16,10 +21,10 @@ require ( github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 github.com/michaelquigley/pfxlog v0.0.0-20190813191113-2be43bd0dccc - github.com/netfoundry/ziti-edge v0.0.0-20191209152826-1b734f68ffb4 - github.com/netfoundry/ziti-fabric v0.0.0-20191203174113-af4eb6e60864 - github.com/netfoundry/ziti-foundation v0.0.0-20191203170231-5c1204e0e65d - github.com/netfoundry/ziti-sdk-golang v0.0.0-20191209154431-2db321362451 + github.com/netfoundry/ziti-edge v0.0.0-20191211205214-958bacc85eaf + github.com/netfoundry/ziti-fabric v0.0.0-20191209202137-4205e73d614e + github.com/netfoundry/ziti-foundation v0.0.0-20191209180049-dd15781cc4aa + github.com/netfoundry/ziti-sdk-golang v0.0.0-20191209205522-dd68e7c5ed49 github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.8.1 github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 diff --git a/go.sum b/go.sum index 559f915d9..386e53272 100644 --- a/go.sum +++ b/go.sum @@ -220,13 +220,21 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/netfoundry/ziti-edge v0.0.0-20191209152826-1b734f68ffb4 h1:AB+YmEEPrUEzll+EvVrjiYXsfjlxGuFPSMcX79UrwLY= github.com/netfoundry/ziti-edge v0.0.0-20191209152826-1b734f68ffb4/go.mod h1:b9NqxGsJSVKqW8kurADYrvPrC6OfJZAIsaeMk7v5bSg= +github.com/netfoundry/ziti-edge v0.0.0-20191211205214-958bacc85eaf h1:ZTmtk6HdgWnJCQRsA5hrX4RNCgOHJsveEo0nCNHu/MU= +github.com/netfoundry/ziti-edge v0.0.0-20191211205214-958bacc85eaf/go.mod h1:iYyr7AlV7ocqajWxo+pFcQFiK/y5mJ7fzmiv365i/lY= github.com/netfoundry/ziti-fabric v0.0.0-20191203174113-af4eb6e60864 h1:GGMpVeTIqeN+ZFC2MJX3qQNX+V9Zkda9lquhw1Toh+k= github.com/netfoundry/ziti-fabric v0.0.0-20191203174113-af4eb6e60864/go.mod h1:ktqE4LYK1Z4MGBpP29ylnUvEsSNwk7jXBfq2K/kq4nw= +github.com/netfoundry/ziti-fabric v0.0.0-20191209202137-4205e73d614e h1:EdTaD5+hjMJpKRQW6yelbeqzrnSfpvXPb45XA0zUCe4= +github.com/netfoundry/ziti-fabric v0.0.0-20191209202137-4205e73d614e/go.mod h1:vJc7LEWv4KWvWkLqpWekH6aNe9uK5z0BrQ8NARlY21Q= github.com/netfoundry/ziti-foundation v0.0.0-20191203170231-5c1204e0e65d h1:V6VZeV8JVUipJhZgDUNUhaJ2L6bqmosAf+SNUj6C1f0= github.com/netfoundry/ziti-foundation v0.0.0-20191203170231-5c1204e0e65d/go.mod h1:27kvN9RZk7cpt2xba6owuXktNphq5hPK62CAiKnIS10= +github.com/netfoundry/ziti-foundation v0.0.0-20191209180049-dd15781cc4aa h1:6Ekd22eDTyTskrvQj2m+uTJ8rf3kDq1vrDWVLwF+oC0= +github.com/netfoundry/ziti-foundation v0.0.0-20191209180049-dd15781cc4aa/go.mod h1:27kvN9RZk7cpt2xba6owuXktNphq5hPK62CAiKnIS10= github.com/netfoundry/ziti-sdk-golang v0.0.0-20191206202611-43555d2de4f9/go.mod h1:WJ49orNIo3R813cG4hfB4mww8NU4mCzQBsKQldqs/ZQ= github.com/netfoundry/ziti-sdk-golang v0.0.0-20191209154431-2db321362451 h1:6prHYMlluujLMhwhB+M4ZcXxIp4B7T6YPImKsMFRJXU= github.com/netfoundry/ziti-sdk-golang v0.0.0-20191209154431-2db321362451/go.mod h1:WJ49orNIo3R813cG4hfB4mww8NU4mCzQBsKQldqs/ZQ= +github.com/netfoundry/ziti-sdk-golang v0.0.0-20191209205522-dd68e7c5ed49 h1:40QUJE6ow9GzW8N0kPaJ1ptYmt4axkFD7982IyVZSZQ= +github.com/netfoundry/ziti-sdk-golang v0.0.0-20191209205522-dd68e7c5ed49/go.mod h1:HaMjEeFnxNo91ew0RbWJ5IZRS04kD4QliFboTVFcLuQ= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oleiade/reflections v1.0.0 h1:0ir4pc6v8/PJ0yw5AEtMddfXpWBXg9cnG7SgSoJuCgY= github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w= diff --git a/ziti/cmd/ziti/cmd/edge_controller/common.go b/ziti/cmd/ziti/cmd/edge_controller/common.go index a20a3fe2e..ea584a4f0 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/common.go +++ b/ziti/cmd/ziti/cmd/edge_controller/common.go @@ -19,9 +19,38 @@ package edge_controller import ( "fmt" "github.com/google/uuid" + "github.com/pkg/errors" "strings" ) +func mapNameToID(entityType string, val string) (string, error) { + // If we can parse it as a UUID, treat it as such + _, err := uuid.Parse(val) + if err == nil { + return val, nil + } + + // Allow UUID formatted names to be recognized with a name: prefix + name := strings.TrimPrefix(val, "name:") + list, err := filterEntitiesOfType(entityType, fmt.Sprintf("name=\"%s\"", name), false) + if err != nil { + return "", err + } + + if len(list) < 1 { + return "", errors.Errorf("no %v found for name %v", entityType, val) + } + + if len(list) > 1 { + return "", errors.Errorf("multiple %v found for name %v, please use id instead", entityType, val) + } + + entity := list[0] + entityId, _ := entity.Path("id").Data().(string) + fmt.Printf("Found %v with id %v for name %v\n", entityType, entityId, val) + return entityId, nil +} + func mapNamesToIDs(entityType string, list ...string) ([]string, error) { var result []string for _, val := range list { @@ -49,37 +78,9 @@ func mapNamesToIDs(entityType string, list ...string) ([]string, error) { } func mapIdentityNameToID(nameOrId string) (string, error) { - ids, err := mapNamesToIDs("identities", nameOrId) - - if err != nil { - return "", err - } - - if len(ids) == 0 { - return "", fmt.Errorf("invalid identity name: %s", nameOrId) - } - - if len(ids) > 1 { - return "", fmt.Errorf("too many identities with name: %s, use id", nameOrId) - } - - return ids[0], nil + return mapNameToID("identities", nameOrId) } func mapCaNameToID(nameOrId string) (string, error) { - ids, err := mapNamesToIDs("cas", nameOrId) - - if err != nil { - return "", err - } - - if len(ids) == 0 { - return "", fmt.Errorf("invalid CA name: %s", nameOrId) - } - - if len(ids) > 1 { - return "", fmt.Errorf("too many CAs with name: %s, use id", nameOrId) - } - - return ids[0], nil + return mapNameToID("cas", nameOrId) } diff --git a/ziti/cmd/ziti/cmd/edge_controller/create.go b/ziti/cmd/ziti/cmd/edge_controller/create.go index f26cc08fd..e45840743 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/create.go +++ b/ziti/cmd/ziti/cmd/edge_controller/create.go @@ -17,11 +17,11 @@ package edge_controller import ( + "fmt" + "github.com/Jeffail/gabs" cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/util" - "fmt" - "github.com/Jeffail/gabs" "github.com/spf13/cobra" "io" ) @@ -39,8 +39,8 @@ func newCreateCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Com } cmd.AddCommand(newCreateAppWanCmd(f, out, errOut)) - cmd.AddCommand(newCreateClusterCmd(f, out, errOut)) cmd.AddCommand(newCreateEdgeRouterCmd(f, out, errOut)) + cmd.AddCommand(newCreateEdgeRouterPolicyCmd(f, out, errOut)) cmd.AddCommand(newCreateIdentityCmd(f, out, errOut)) cmd.AddCommand(newCreateServiceCmd(f, out, errOut)) cmd.AddCommand(newCreateAuthenticatorCmd(f, out, errOut)) diff --git a/ziti/cmd/ziti/cmd/edge_controller/create_cluster.go b/ziti/cmd/ziti/cmd/edge_controller/create_cluster.go deleted file mode 100644 index 8297ad9ca..000000000 --- a/ziti/cmd/ziti/cmd/edge_controller/create_cluster.go +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright 2019 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 ( - "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common" - cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" - "fmt" - "github.com/Jeffail/gabs" - "github.com/spf13/cobra" - "io" -) - -// newCreateClusterCmd creates the 'edge controller create cluster' command -func newCreateClusterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &commonOptions{ - CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, - } - - cmd := &cobra.Command{ - Use: "cluster ", - Short: "creates a cluster managed by the Ziti Edge Controller", - Long: "creates a cluster managed by the Ziti Edge Controller", - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := runCreateCluster(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") - - return cmd -} - -// runCreateCluster create a new cluster on the Ziti Edge Controller -func runCreateCluster(o *commonOptions) error { - - serviceData := gabs.New() - setJSONValue(serviceData, o.Args[0], "name") - - result, err := createEntityOfType("clusters", serviceData.String(), o) - - if err != nil { - panic(err) - } - - clusterId := result.S("data", "id").Data() - - if _, err := fmt.Fprintf(o.Out, "%v\n", clusterId); err != nil { - panic(err) - } - - return err -} diff --git a/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go b/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go index 62a7cb0f7..9bb32de14 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go +++ b/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go @@ -17,11 +17,11 @@ package edge_controller import ( + "fmt" + "github.com/Jeffail/gabs" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common" cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" - "fmt" - "github.com/Jeffail/gabs" "github.com/spf13/cobra" "io" "io/ioutil" @@ -29,7 +29,8 @@ import ( type createEdgeRouterOptions struct { commonOptions - jwtOutputFile string + roleAttributes []string + jwtOutputFile string } func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { @@ -40,10 +41,11 @@ func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) } cmd := &cobra.Command{ - Use: "edge-router [cluster]?", + Use: "edge-router ", Aliases: []string{"gateway"}, Short: "creates an edge router managed by the Ziti Edge Controller", Long: "creates an edge router managed by the Ziti Edge Controller", + Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { options.Cmd = cmd options.Args = args @@ -55,6 +57,7 @@ func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) // allow interspersing positional args and flags cmd.Flags().SetInterspersed(true) + cmd.Flags().StringSliceVarP(&options.roleAttributes, "role-attributes", "r", nil, "Role attributes of the new edge router") cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller") cmd.Flags().StringVarP(&options.jwtOutputFile, "jwt-output-file", "o", "", "File to which to output the JWT used for enrolling the edge router") return cmd @@ -64,18 +67,7 @@ func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) func runCreateEdgeRouter(o *createEdgeRouterOptions) error { routerData := gabs.New() setJSONValue(routerData, o.Args[0], "name") - if len(o.Args) > 1 { - clusterIds, err := mapNamesToIDs("clusters", o.Args[1]) - if err != nil { - return err - } - if len(clusterIds) == 0 { - return fmt.Errorf("cluster not found by id/name: %v", o.Args[1]) - } - setJSONValue(routerData, clusterIds[0], "clusterId") - } else { - setJSONValue(routerData, getFirstCluster(o), "clusterId") - } + setJSONValue(routerData, o.roleAttributes, "roleAttributes") result, err := createEntityOfType("edge-routers", routerData.String(), &o.commonOptions) @@ -133,16 +125,3 @@ func getEdgeRouterJwt(o *createEdgeRouterOptions, id string) error { return err } - -func getFirstCluster(o *createEdgeRouterOptions) string { - clusterList, err := listEntitiesOfType("clusters", &o.commonOptions) - if err != nil { - panic(err) - } - - if len(clusterList) == 0 { - panic("no clusters available. please create cluster before creating a service.") - } - - return clusterList[0].Path("id").Data().(string) -} diff --git a/ziti/cmd/ziti/cmd/edge_controller/create_edge_router_policy.go b/ziti/cmd/ziti/cmd/edge_controller/create_edge_router_policy.go new file mode 100644 index 000000000..782c6cb5f --- /dev/null +++ b/ziti/cmd/ziti/cmd/edge_controller/create_edge_router_policy.go @@ -0,0 +1,87 @@ +/* + Copyright 2019 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" + "github.com/Jeffail/gabs" + "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common" + cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" + cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" + "github.com/spf13/cobra" + "io" +) + +type createEdgeRouterPolicyOptions struct { + commonOptions + edgeRouterRoles []string + identityRoles []string + jwtOutputFile string +} + +// newCreateEdgeRouterPolicyCmd creates the 'edge controller create edge-router-policy' command +func newCreateEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { + options := &createEdgeRouterPolicyOptions{ + commonOptions: commonOptions{ + CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, + }, + } + + cmd := &cobra.Command{ + Use: "edge-router-policy ", + Short: "creates an edge-router-policy managed by the Ziti Edge Controller", + Long: "creates an edge-router-policy managed by the Ziti Edge Controller", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := runCreateEdgeRouterPolicy(options) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringSliceVarP(&options.edgeRouterRoles, "edge-router-roles", "r", nil, "Edge router roles of the new edge router policy") + cmd.Flags().StringSliceVarP(&options.identityRoles, "identity-roles", "i", nil, "Identity roles of the new edge router policy") + cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller") + + return cmd +} + +// runCreateEdgeRouterPolicy create a new edgeRouterPolicy on the Ziti Edge Controller +func runCreateEdgeRouterPolicy(o *createEdgeRouterPolicyOptions) error { + + entityData := gabs.New() + setJSONValue(entityData, o.Args[0], "name") + setJSONValue(entityData, o.edgeRouterRoles, "edgeRouterRoles") + setJSONValue(entityData, o.identityRoles, "identityRoles") + result, err := createEntityOfType("edge-router-policies", entityData.String(), &o.commonOptions) + + if err != nil { + panic(err) + } + + edgeRouterPolicyId := result.S("data", "id").Data() + + if _, err := fmt.Fprintf(o.Out, "%v\n", edgeRouterPolicyId); err != nil { + panic(err) + } + + return err +} diff --git a/ziti/cmd/ziti/cmd/edge_controller/create_identity.go b/ziti/cmd/ziti/cmd/edge_controller/create_identity.go index d981ef2e1..3d3533bd0 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/create_identity.go +++ b/ziti/cmd/ziti/cmd/edge_controller/create_identity.go @@ -17,11 +17,11 @@ package edge_controller import ( + "fmt" + "github.com/Jeffail/gabs" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common" cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" - "fmt" - "github.com/Jeffail/gabs" "github.com/spf13/cobra" "io" "io/ioutil" @@ -31,8 +31,9 @@ import ( type createIdentityOptions struct { commonOptions - isAdmin bool - jwtOutputFile string + isAdmin bool + roleAttributes []string + jwtOutputFile string } // newCreateIdentityCmd creates the 'edge controller create identity' command @@ -78,20 +79,21 @@ func newCreateIdentityOfTypeCmd(idType string, options *createIdentityOptions) * cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller") cmd.Flags().BoolVarP(&options.isAdmin, "admin", "A", false, "Give the new identity admin privileges") + cmd.Flags().StringSliceVarP(&options.roleAttributes, "role-attributes", "r", nil, "Role attributes of the new identity") cmd.Flags().StringVarP(&options.jwtOutputFile, "jwt-output-file", "o", "", "File to which to output the JWT used for enrolling the identity") return cmd } func runCreateIdentity(idType string, o *createIdentityOptions) error { - - serviceData := gabs.New() - setJSONValue(serviceData, o.Args[0], "name") - setJSONValue(serviceData, strings.Title(idType), "type") - setJSONValue(serviceData, true, "enrollment", "ott") - setJSONValue(serviceData, o.isAdmin, "isAdmin") - - result, err := createEntityOfType("identities", serviceData.String(), &o.commonOptions) + entityData := gabs.New() + setJSONValue(entityData, o.Args[0], "name") + setJSONValue(entityData, strings.Title(idType), "type") + setJSONValue(entityData, true, "enrollment", "ott") + setJSONValue(entityData, o.isAdmin, "isAdmin") + setJSONValue(entityData, o.roleAttributes, "roleAttributes") + + result, err := createEntityOfType("identities", entityData.String(), &o.commonOptions) if err != nil { panic(err) diff --git a/ziti/cmd/ziti/cmd/edge_controller/create_service.go b/ziti/cmd/ziti/cmd/edge_controller/create_service.go index 996dd1305..dd23ed9ea 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/create_service.go +++ b/ziti/cmd/ziti/cmd/edge_controller/create_service.go @@ -17,11 +17,11 @@ package edge_controller import ( + "fmt" + "github.com/Jeffail/gabs" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common" cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" - "fmt" - "github.com/Jeffail/gabs" "github.com/spf13/cobra" "io" "strconv" @@ -29,10 +29,10 @@ import ( type createServiceOptions struct { commonOptions - hostedService bool - tags map[string]string - clusters []string - hostIds []string + hostedService bool + tags map[string]string + edgeRouterRoles []string + hostIds []string } // newCreateServiceCmd creates the 'edge controller create service local' command for the given entity type @@ -67,7 +67,7 @@ func newCreateServiceCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *co cmd.Flags().StringToStringVarP(&options.tags, "tags", "t", nil, "Add tags to service definition") cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller") cmd.Flags().BoolVar(&options.hostedService, "hosted", false, "Indicates that this is a hosted service") - cmd.Flags().StringSliceVarP(&options.clusters, "clusters", "c", nil, "Clusters to add this service to") + cmd.Flags().StringSliceVarP(&options.edgeRouterRoles, "edge-router-roles", "r", nil, "Edge router roles of the new service") cmd.Flags().StringSliceVarP(&options.hostIds, "host-ids", "i", nil, "Identities allowed to host this service") return cmd @@ -75,13 +75,6 @@ func newCreateServiceCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *co // runCreateNativeService implements the command to create a service func runCreateService(o *createServiceOptions) (err error) { - var clusterIds []string - if len(o.clusters) == 0 { - clusterIds = getClusters(o) - } else if clusterIds, err = mapNamesToIDs("clusters", o.clusters...); err != nil { - return err - } - var port int if port, err = strconv.Atoi(o.Args[2]); err != nil { return err @@ -89,7 +82,7 @@ func runCreateService(o *createServiceOptions) (err error) { serviceData := gabs.New() setJSONValue(serviceData, o.Args[0], "name") - setJSONValue(serviceData, clusterIds, "clusters") + setJSONValue(serviceData, o.edgeRouterRoles, "edgeRouterRoles") setJSONValue(serviceData, o.Args[1], "dns", "hostname") setJSONValue(serviceData, port, "dns", "port") @@ -125,23 +118,3 @@ func runCreateService(o *createServiceOptions) (err error) { return err } - -func getClusters(o *createServiceOptions) []string { - clusterList, err := listEntitiesOfType("clusters", &o.commonOptions) - if err != nil { - panic(err) - } - - if len(clusterList) == 0 { - panic("no clusters available. please create cluster before creating a service.") - } - - var clusterIds []string - - for _, cluster := range clusterList { - clusterId, _ := cluster.Path("id").Data().(string) - clusterIds = append(clusterIds, clusterId) - } - - return clusterIds -} diff --git a/ziti/cmd/ziti/cmd/edge_controller/delete.go b/ziti/cmd/ziti/cmd/edge_controller/delete.go index baed6f48e..d131bf00d 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/delete.go +++ b/ziti/cmd/ziti/cmd/edge_controller/delete.go @@ -17,14 +17,15 @@ package edge_controller import ( + "fmt" + "github.com/Jeffail/gabs" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common" cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/util" - "fmt" - "github.com/Jeffail/gabs" "github.com/spf13/cobra" "io" + "strings" ) // newDeleteCmd creates a command object for the "edge controller delete" command @@ -51,8 +52,8 @@ func newDeleteCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Com cmd.AddCommand(newDeleteCmdForEntityType("app-wan", runDeleteEntityOfType, newOptions())) cmd.AddCommand(newDeleteCmdForEntityType("ca", runDeleteEntityOfType, newOptions())) - cmd.AddCommand(newDeleteCmdForEntityType("cluster", runDeleteEntityOfType, newOptions())) cmd.AddCommand(newDeleteCmdForEntityType("edge-router", runDeleteEntityOfType, newOptions())) + cmd.AddCommand(newDeleteCmdForEntityType("edge-router-policy", runDeleteEntityOfType, newOptions())) cmd.AddCommand(newDeleteCmdForEntityType("gateway", runDeleteEntityOfType, newOptions())) cmd.AddCommand(newDeleteCmdForEntityType("identity", runDeleteEntityOfType, newOptions())) cmd.AddCommand(newDeleteCmdForEntityType("network-session", runDeleteEntityOfType, newOptions())) @@ -115,8 +116,8 @@ func runDeleteEntityOfType(o *commonOptions, entityType string) error { } func getPlural(entityType string) string { - if entityType == "identity" { - return "identities" + if strings.HasSuffix(entityType, "y") { + return strings.TrimSuffix(entityType, "y") + "ies" } return entityType + "s" } diff --git a/ziti/cmd/ziti/cmd/edge_controller/list.go b/ziti/cmd/ziti/cmd/edge_controller/list.go index fc0f70a21..eab3a7a1e 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/list.go +++ b/ziti/cmd/ziti/cmd/edge_controller/list.go @@ -17,12 +17,12 @@ package edge_controller import ( + "fmt" + "github.com/Jeffail/gabs" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common" cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/util" - "fmt" - "github.com/Jeffail/gabs" "github.com/spf13/cobra" "io" ) @@ -51,22 +51,51 @@ func newListCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comma cmd.AddCommand(newListCmdForEntityType("app-wans", runListAppWans, newOptions())) cmd.AddCommand(newListCmdForEntityType("cas", runListCAs, newOptions())) - cmd.AddCommand(newListCmdForEntityType("clusters", runListClusters, newOptions())) cmd.AddCommand(newListCmdForEntityType("edge-routers", runListEdgeRouters, newOptions())) + cmd.AddCommand(newListCmdForEntityType("edge-router-policies", runListEdgeRouterPolicies, newOptions())) cmd.AddCommand(newListCmdForEntityType("gateways", runListEdgeRouters, newOptions())) cmd.AddCommand(newListCmdForEntityType("identities", runListIdentities, newOptions())) cmd.AddCommand(newListCmdForEntityType("services", runListServices, newOptions())) - cmd.AddCommand(newListCmdForEntityType("sessions", runListSessions, newOptions())) + cmd.AddCommand(newListCmdForEntityType("services", runListServices, newOptions())) + cmd.AddCommand(newListCmdForEntityType("sessions", runListApiSessions, newOptions())) cmd.AddCommand(newListCmdForEntityType("network-sessions", runListNetworkSessions, newOptions())) + edgeRouterListRootCmd := newEntityListRootCmd("edge-router") + edgeRouterListRootCmd.AddCommand(newSubListCmdForEntityType("edge-router", "edge-router-policies", runListEdgeRouterEdgeRouterPolicies, newOptions())) + edgeRouterListRootCmd.AddCommand(newSubListCmdForEntityType("edge-router", "services", runListEdgeRouterServices, newOptions())) + + edgeRouterPolicyListRootCmd := newEntityListRootCmd("edge-router-policy") + edgeRouterPolicyListRootCmd.AddCommand(newSubListCmdForEntityType("edge-router-policies", "edge-routers", runListEdgeRouterPolicyEdgeRouters, newOptions())) + edgeRouterPolicyListRootCmd.AddCommand(newSubListCmdForEntityType("edge-router-policies", "identities", runListEdgeRouterPolicyIdentities, newOptions())) + + identityListRootCmd := newEntityListRootCmd("identity") + identityListRootCmd.AddCommand(newSubListCmdForEntityType("identities", "edge-router-policies", runListIdentityEdgeRouterPolicies, newOptions())) + + serviceListRootCmd := newEntityListRootCmd("service") + serviceListRootCmd.AddCommand(newSubListCmdForEntityType("services", "edge-routers", runListServiceEdgeRouters, newOptions())) + + cmd.AddCommand(edgeRouterListRootCmd, edgeRouterPolicyListRootCmd, serviceListRootCmd) + return cmd } type listCommandRunner func(*commonOptions) error +func newEntityListRootCmd(entityType string) *cobra.Command { + desc := fmt.Sprintf("list entities related to a %v instance managed by the Ziti Edge Controller", entityType) + return &cobra.Command{ + Use: entityType, + Short: desc, + Long: desc, + Run: func(cmd *cobra.Command, args []string) { + err := cmd.Help() + cmdhelper.CheckErr(err) + }, + } +} + // newListCmdForEntityType creates the list command for the given entity type func newListCmdForEntityType(entityType string, command listCommandRunner, options *commonOptions) *cobra.Command { - cmd := &cobra.Command{ Use: entityType + " ?", Short: "lists " + entityType + " managed by the Ziti Edge Controller", @@ -89,6 +118,31 @@ func newListCmdForEntityType(entityType string, command listCommandRunner, optio return cmd } +// newSubListCmdForEntityType creates the list command for the given entity type +func newSubListCmdForEntityType(entityType string, subType string, command listCommandRunner, options *commonOptions) *cobra.Command { + desc := fmt.Sprintf("lists %v related to a %v instanced managed by the Ziti Edge Controller", subType, entityType) + cmd := &cobra.Command{ + Use: fmt.Sprintf("%v ", subType), + Short: desc, + Long: desc, + Args: cobra.MaximumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := command(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") + + return cmd +} + // listEntitiesOfType queries the Ziti Controller for entities of the given type func listEntitiesOfType(entityType string, options *commonOptions) ([]*gabs.Container, error) { return filterEntitiesOfType(entityType, "", options.OutputJSONResponse) @@ -104,7 +158,6 @@ func listEntitiesOfTypeWithOptionalFilter(entityType string, options *commonOpti // listEntitiesOfType queries the Ziti Controller for entities of the given type func filterEntitiesOfType(entityType string, filter string, outputJSON bool) ([]*gabs.Container, error) { - session := &session{} err := session.Load() @@ -116,7 +169,7 @@ func filterEntitiesOfType(entityType string, filter string, outputJSON bool) ([] return nil, fmt.Errorf("host not specififed in cli config file. Exiting") } - jsonParsed, err := util.EdgeControllerListEntities(session.Host, session.Cert, session.Token, entityType, filter, outputJSON) + jsonParsed, err := util.EdgeControllerListEntities(session, entityType, filter, outputJSON) if err != nil { return nil, err @@ -125,84 +178,118 @@ func filterEntitiesOfType(entityType string, filter string, outputJSON bool) ([] return jsonParsed.S("data").Children() } -func runListClusters(o *commonOptions) error { - - children, err := listEntitiesOfTypeWithOptionalFilter("clusters", o) +// listEntitiesOfType queries the Ziti Controller for entities of the given type +func filterSubEntitiesOfType(entityType, subType, entityId, filter string, outputJSON bool) ([]*gabs.Container, error) { + session := &session{} + err := session.Load() if err != nil { - return err + return nil, err } - for _, cluster := range children { - id, _ := cluster.Path("id").Data().(string) - name, _ := cluster.Path("name").Data().(string) - if _, err = fmt.Fprintf(o.Out, "id: %v name: %v\n", id, name); err != nil { - panic(err) - } + if session.Host == "" { + return nil, fmt.Errorf("host not specififed in cli config file. Exiting") } - return err + jsonParsed, err := util.EdgeControllerListSubEntities(session, entityType, subType, entityId, filter, outputJSON) + + if err != nil { + return nil, err + } + + return jsonParsed.S("data").Children() } func runListEdgeRouters(o *commonOptions) error { - children, err := listEntitiesOfTypeWithOptionalFilter("edge-routers", o) - if err != nil { return err } + return outputEdgeRouters(o, children) +} +func outputEdgeRouters(o *commonOptions, children []*gabs.Container) error { for _, entity := range children { id, _ := entity.Path("id").Data().(string) name, _ := entity.Path("name").Data().(string) - cluster, _ := entity.Path("cluster.id").Data().(string) - fmt.Fprintf(o.Out, "id: %v name: %v cluster-id: %v\n", id, name, cluster) + roleAttributes := entity.Path("roleAttributes").String() + if _, err := fmt.Fprintf(o.Out, "id: %v name: %v role attributes: %v\n", id, name, roleAttributes); err != nil { + return err + } } + return nil +} - return err +func runListEdgeRouterPolicies(o *commonOptions) error { + children, err := listEntitiesOfTypeWithOptionalFilter("edge-router-policies", o) + if err != nil { + return err + } + return outputEdgeRouterPolicies(o, children) } -func runListServices(o *commonOptions) error { +func outputEdgeRouterPolicies(o *commonOptions, children []*gabs.Container) error { + for _, entity := range children { + id, _ := entity.Path("id").Data().(string) + name, _ := entity.Path("name").Data().(string) + edgeRouterRoles := entity.Path("edgeRouterRoles").String() + identityRoles := entity.Path("identityRoles").String() + _, err := fmt.Fprintf(o.Out, "id: %v name: %v edge router roles: %v identity roles: %v\n", id, name, edgeRouterRoles, identityRoles) + if err != nil { + return err + } + } + return nil +} +func runListServices(o *commonOptions) error { children, err := listEntitiesOfTypeWithOptionalFilter("services", o) - if err != nil { return err } + return outputServices(o, children) +} +func outputServices(o *commonOptions, children []*gabs.Container) error { for _, entity := range children { id, _ := entity.Path("id").Data().(string) name, _ := entity.Path("name").Data().(string) - cluster := entity.Path("clusters.name").String() - fmt.Fprintf(o.Out, "id: %v name: %v clusters: %v\n", id, name, cluster) + edgeRouterRoles := entity.Path("edgeRouterRoles").String() + _, err := fmt.Fprintf(o.Out, "id: %v name: %v edge router roles: %v\n", id, name, edgeRouterRoles) + if err != nil { + return err + } } - return err + return nil } // runListIdentities implements the command to list identities func runListIdentities(o *commonOptions) error { - children, err := listEntitiesOfTypeWithOptionalFilter("identities", o) - if err != nil { return err } + return outputIdentities(o, children) +} +// outputIdentities implements the command to list identities +func outputIdentities(o *commonOptions, children []*gabs.Container) error { for _, entity := range children { id, _ := entity.Path("id").Data().(string) name, _ := entity.Path("name").Data().(string) typeName, _ := entity.Path("type.name").Data().(string) - fmt.Fprintf(o.Out, "id: %v name: %v type: %v\n", id, name, typeName) + roleAttributes := entity.Path("roleAttributes").String() + if _, err := fmt.Fprintf(o.Out, "id: %v name: %v type: %v role attributes: %v\n", id, name, typeName, roleAttributes); err != nil { + return err + } } - return err + return nil } func runListAppWans(o *commonOptions) error { - children, err := listEntitiesOfTypeWithOptionalFilter("app-wans", o) - if err != nil { return err } @@ -210,16 +297,16 @@ func runListAppWans(o *commonOptions) error { for _, entity := range children { id, _ := entity.Path("id").Data().(string) name, _ := entity.Path("name").Data().(string) - fmt.Fprintf(o.Out, "id: %v name: %v\n", id, name) + if _, err := fmt.Fprintf(o.Out, "id: %v name: %v\n", id, name); err != nil { + return err + } } - return err + return nil } func runListCAs(o *commonOptions) error { - children, err := listEntitiesOfTypeWithOptionalFilter("cas", o) - if err != nil { return err } @@ -228,16 +315,16 @@ func runListCAs(o *commonOptions) error { id, _ := entity.Path("id").Data().(string) name, _ := entity.Path("name").Data().(string) cluster, _ := entity.Path("cluster.id").Data().(string) - fmt.Fprintf(o.Out, "id: %v name: %v cluster-id: %v\n", id, name, cluster) + if _, err := fmt.Fprintf(o.Out, "id: %v name: %v cluster-id: %v\n", id, name, cluster); err != nil { + return err + } } - return err + return nil } -func runListSessions(o *commonOptions) error { - +func runListApiSessions(o *commonOptions) error { children, err := listEntitiesOfTypeWithOptionalFilter("sessions", o) - if err != nil { return err } @@ -253,7 +340,6 @@ func runListSessions(o *commonOptions) error { } func runListNetworkSessions(o *commonOptions) error { - children, err := listEntitiesOfTypeWithOptionalFilter("network-sessions", o) if err != nil { @@ -265,8 +351,48 @@ func runListNetworkSessions(o *commonOptions) error { sessionId, _ := entity.Path("session.id").Data().(string) serviceName, _ := entity.Path("service.name").Data().(string) hosting, _ := entity.Path("hosting").Data().(bool) - fmt.Fprintf(o.Out, "id: %v sessionId: %v serviceName: %v hosting: %v\n", id, sessionId, serviceName, hosting) + if _, err := fmt.Fprintf(o.Out, "id: %v sessionId: %v serviceName: %v hosting: %v\n", id, sessionId, serviceName, hosting); err != nil { + return err + } } return err } + +func runListServiceEdgeRouters(o *commonOptions) error { + return runListChilden("services", "edge-routers", o, outputEdgeRouters) +} + +func runListEdgeRouterEdgeRouterPolicies(o *commonOptions) error { + return runListChilden("edge-routers", "edge-router-policies", o, outputEdgeRouterPolicies) +} + +func runListEdgeRouterServices(o *commonOptions) error { + return runListChilden("edge-routers", "services", o, outputServices) +} + +func runListEdgeRouterPolicyEdgeRouters(o *commonOptions) error { + return runListChilden("edge-router-policies", "edge-routers", o, outputEdgeRouters) +} + +func runListEdgeRouterPolicyIdentities(o *commonOptions) error { + return runListChilden("edge-router-policies", "identities", o, outputEdgeRouters) +} + +func runListIdentityEdgeRouterPolicies(o *commonOptions) error { + return runListChilden("identities", "edge-router-policies", o, outputIdentities) +} + +func runListChilden(parentType, childType string, o *commonOptions, outputFunc func(*commonOptions, []*gabs.Container) error) error { + idOrName := o.Args[0] + serviceId, err := mapNameToID(parentType, idOrName) + if err != nil { + return err + } + + children, err := filterSubEntitiesOfType(parentType, childType, serviceId, "", o.OutputJSONResponse) + if err != nil { + return err + } + return outputFunc(o, children) +} diff --git a/ziti/cmd/ziti/cmd/edge_controller/password.go b/ziti/cmd/ziti/cmd/edge_controller/password.go index c0618af3c..0691345ed 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/password.go +++ b/ziti/cmd/ziti/cmd/edge_controller/password.go @@ -17,8 +17,8 @@ package edge_controller import ( - "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/util" "fmt" + "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/util" ) const ( @@ -33,6 +33,18 @@ type session struct { Cert string } +func (session *session) GetBaseUrl() string { + return session.Host +} + +func (session *session) GetCert() string { + return session.Cert +} + +func (session *session) GetToken() string { + return session.Token +} + // Persist writes out the Ziti CLI session file func (session *session) Persist() error { return util.WriteZitiAppFile(appName, sessionType, session) diff --git a/ziti/cmd/ziti/util/rest.go b/ziti/cmd/ziti/util/rest.go index 80d4aad63..1a2f75c24 100644 --- a/ziti/cmd/ziti/util/rest.go +++ b/ziti/cmd/ziti/util/rest.go @@ -18,16 +18,16 @@ package util import ( "archive/tar" - cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" - c "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/constants" - "github.com/netfoundry/ziti-foundation/common/constants" - "github.com/netfoundry/ziti-cmd/common/version" "bytes" "compress/gzip" "encoding/json" "fmt" "github.com/Jeffail/gabs" "github.com/blang/semver" + "github.com/netfoundry/ziti-cmd/common/version" + cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers" + c "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/constants" + "github.com/netfoundry/ziti-foundation/common/constants" "gopkg.in/resty.v1" "io" "net/http" @@ -419,34 +419,51 @@ func EdgeControllerLogin(url string, cert string, authentication string) (*gabs. return jsonParsed, nil } +type Session interface { + GetBaseUrl() string + GetCert() string + GetToken() string +} + // EdgeControllerListEntities will list entities of the given type in the given Edge Controller -func EdgeControllerListEntities(baseUrl string, cert string, token string, entityType string, filter string, logJSON bool) (*gabs.Container, error) { +func EdgeControllerListEntities(session Session, entityType string, filter string, logJSON bool) (*gabs.Container, error) { + return EdgeControllerList(session, entityType, filter, logJSON) +} + +// EdgeControllerListSubEntities will list entities of the given type in the given Edge Controller +func EdgeControllerListSubEntities(session Session, entityType, subType, entityId string, filter string, logJSON bool) (*gabs.Container, error) { + return EdgeControllerList(session, entityType+"/"+entityId+"/"+subType, filter, logJSON) +} + +// EdgeControllerList will list entities of the given type in the given Edge Controller +func EdgeControllerList(session Session, path, filter string, logJSON bool) (*gabs.Container, error) { client := newClient() - if cert != "" { - client.SetRootCertificate(cert) + if session.GetCert() != "" { + client.SetRootCertificate(session.GetCert()) } - queryURL := baseUrl + "/" + entityType + queryUrl := session.GetBaseUrl() + "/" + path + if filter != "" { params := url.Values{} params.Add("filter", filter) - queryURL += "?" + params.Encode() + queryUrl += "?" + params.Encode() } resp, err := client. R(). SetHeader("Content-Type", "application/json"). - SetHeader(constants.ZitiSession, token). - Get(queryURL) + SetHeader(constants.ZitiSession, session.GetToken()). + Get(queryUrl) if err != nil { - return nil, fmt.Errorf("unable to list %v in Ziti Edge Controller at %v. Error: %v", entityType, baseUrl, err) + return nil, fmt.Errorf("unable to list entities at %v in Ziti Edge Controller at %v. Error: %v", queryUrl, err) } if resp.StatusCode() != http.StatusOK { - return nil, fmt.Errorf("error listing %v in Ziti Edge Controller at %v. Status code: %v, Server returned: %v", - entityType, baseUrl, resp.Status(), resp.String()) + return nil, fmt.Errorf("error listing %v in Ziti Edge Controller. Status code: %v, Server returned: %v", + queryUrl, resp.Status(), resp.String()) } if logJSON { @@ -459,7 +476,7 @@ func EdgeControllerListEntities(baseUrl string, cert string, token string, entit jsonParsed, err := gabs.ParseJSON(resp.Body()) if err != nil { - return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", baseUrl, resp.String()) + return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", queryUrl, resp.String()) } return jsonParsed, nil