diff --git a/common/enrollment/enroll.go b/common/enrollment/enroll.go index b1abef3a7..69a2d7303 100644 --- a/common/enrollment/enroll.go +++ b/common/enrollment/enroll.go @@ -34,6 +34,7 @@ import ( // global state used by all subcommands are located here for easy discovery var verbose bool +var removeJwt bool var keyAlg config.KeyAlgVar var jwtpath, outpath, keyPath, certPath, idname, caOverride, username, password string @@ -85,6 +86,7 @@ func NewEnrollCommand() *cobra.Command { enrollSubCmd.Flags().StringVarP(&caOverride, "ca", "", "", "Additional trusted certificates") enrollSubCmd.Flags().StringVarP(&username, "username", "u", "", "Username for updb enrollment, prompted if not provided and necessary") enrollSubCmd.Flags().StringVarP(&password, "password", "p", "", "Password for updb enrollment, prompted if not provided and necessary") + enrollSubCmd.Flags().BoolVar(&removeJwt, "rm", false, "Remove the JWT on success") keyAlg.Set("RSA") // set default enrollSubCmd.Flags().VarP(&keyAlg, "keyAlg", "a", "Crypto algorithm to use when generating private key") @@ -170,7 +172,13 @@ func processEnrollment() error { flags.Password = password } - return enroll.EnrollUpdb(flags) + err = enroll.EnrollUpdb(flags) + if err == nil { + if rmErr := os.Remove(jwtpath); rmErr != nil { + pfxlog.Logger().WithError(rmErr).Warnf("unable to remove JWT file as requested: %v", jwtpath) + } + } + return err } conf, err := enroll.Enroll(flags) @@ -188,6 +196,10 @@ func processEnrollment() error { enc.SetEscapeHTML(false) encErr := enc.Encode(&conf) + if err = os.Remove(jwtpath); err != nil { + pfxlog.Logger().WithError(err).Warnf("unable to remove JWT file as requested: %v", jwtpath) + } + if encErr == nil { pfxlog.Logger().Infof("enrolled successfully. identity file written to: %s", outpath) return nil diff --git a/ziti-fabric-test/subcmd/loop3/dialer.go b/ziti-fabric-test/subcmd/loop3/dialer.go index 97921d883..6b1699d8a 100644 --- a/ziti-fabric-test/subcmd/loop3/dialer.go +++ b/ziti-fabric-test/subcmd/loop3/dialer.go @@ -23,9 +23,9 @@ import ( "github.com/openziti/foundation/agent" "github.com/openziti/foundation/identity/dotziti" "github.com/openziti/foundation/identity/identity" - "github.com/openziti/transport" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/transport" "github.com/spf13/cobra" "net" "strings" @@ -180,9 +180,11 @@ func (cmd *dialerCmd) connect() net.Conn { panic(err) } - _, id, err := dotziti.LoadIdentity(cmd.identity) - if err != nil { - panic(err) + id := &identity.TokenId{Token: "test"} + if endpoint.Type() != "tcp" || !cmd.direct { + if _, id, err = dotziti.LoadIdentity(cmd.identity); err != nil { + panic(err) + } } if cmd.direct { diff --git a/ziti-fabric-test/subcmd/loop3/listener.go b/ziti-fabric-test/subcmd/loop3/listener.go index 61552c624..5dc93e8d5 100644 --- a/ziti-fabric-test/subcmd/loop3/listener.go +++ b/ziti-fabric-test/subcmd/loop3/listener.go @@ -22,9 +22,9 @@ import ( "github.com/openziti/foundation/agent" "github.com/openziti/foundation/identity/dotziti" "github.com/openziti/foundation/identity/identity" - "github.com/openziti/transport" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/transport" loop3_pb "github.com/openziti/ziti/ziti-fabric-test/subcmd/loop3/pb" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -70,7 +70,7 @@ func (cmd *listenerCmd) run(_ *cobra.Command, args []string) { var err error shutdownClean := false if err = agent.Listen(agent.Options{ShutdownCleanup: &shutdownClean}); err != nil { - pfxlog.Logger().WithError(err).Error("unable to start CLI agent") + log.WithError(err).Error("unable to start CLI agent") } var scenario *Scenario @@ -96,17 +96,21 @@ func (cmd *listenerCmd) run(_ *cobra.Command, args []string) { defer close(closer) } + log.Infof("binding to address '%v'", cmd.bindAddress) if strings.HasPrefix(cmd.bindAddress, "edge") { cmd.listenEdge() } else { - _, id, err := dotziti.LoadIdentity(cmd.identity) + bindAddress, err := transport.ParseAddress(cmd.bindAddress) if err != nil { panic(err) } - bindAddress, err := transport.ParseAddress(cmd.bindAddress) - if err != nil { - panic(err) + id := &identity.TokenId{Token: "test"} + if bindAddress.Type() != "tcp" { + _, id, err = dotziti.LoadIdentity(cmd.identity) + if err != nil { + panic(err) + } } cmd.listen(bindAddress, id) diff --git a/ziti-fabric-test/subcmd/loop3/pb/generate.go b/ziti-fabric-test/subcmd/loop3/pb/generate.go new file mode 100644 index 000000000..b4641b229 --- /dev/null +++ b/ziti-fabric-test/subcmd/loop3/pb/generate.go @@ -0,0 +1,5 @@ +//go:generate protoc -I ./ ./loop3.proto --go_out=paths=source_relative:./ + +package loop3_pb + +// Here to provide the go:generate line above diff --git a/ziti-fabric-test/subcmd/loop3/pb/loop3.pb.go b/ziti-fabric-test/subcmd/loop3/pb/loop3.pb.go index f50bb1d6a..0d9811339 100644 --- a/ziti-fabric-test/subcmd/loop3/pb/loop3.pb.go +++ b/ziti-fabric-test/subcmd/loop3/pb/loop3.pb.go @@ -1,177 +1,277 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.1 // source: loop3.proto package loop3_pb import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) type Test struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - TxRequests int32 `protobuf:"varint,2,opt,name=txRequests,proto3" json:"txRequests,omitempty"` - TxPacing int32 `protobuf:"varint,3,opt,name=txPacing,proto3" json:"txPacing,omitempty"` - TxMaxJitter int32 `protobuf:"varint,4,opt,name=txMaxJitter,proto3" json:"txMaxJitter,omitempty"` - RxRequests int32 `protobuf:"varint,5,opt,name=rxRequests,proto3" json:"rxRequests,omitempty"` - RxTimeout int32 `protobuf:"varint,6,opt,name=rxTimeout,proto3" json:"rxTimeout,omitempty"` - PayloadMinBytes int32 `protobuf:"varint,7,opt,name=payloadMinBytes,proto3" json:"payloadMinBytes,omitempty"` - PayloadMaxBytes int32 `protobuf:"varint,8,opt,name=payloadMaxBytes,proto3" json:"payloadMaxBytes,omitempty"` - LatencyFrequency int32 `protobuf:"varint,9,opt,name=latencyFrequency,proto3" json:"latencyFrequency,omitempty"` - TxBlockType string `protobuf:"bytes,10,opt,name=txBlockType,proto3" json:"txBlockType,omitempty"` - RxBlockType string `protobuf:"bytes,11,opt,name=rxBlockType,proto3" json:"rxBlockType,omitempty"` - RxSeqBlockSize int32 `protobuf:"varint,12,opt,name=rxSeqBlockSize,proto3" json:"rxSeqBlockSize,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + TxRequests int32 `protobuf:"varint,2,opt,name=txRequests,proto3" json:"txRequests,omitempty"` + TxPacing int32 `protobuf:"varint,3,opt,name=txPacing,proto3" json:"txPacing,omitempty"` + TxMaxJitter int32 `protobuf:"varint,4,opt,name=txMaxJitter,proto3" json:"txMaxJitter,omitempty"` + RxRequests int32 `protobuf:"varint,5,opt,name=rxRequests,proto3" json:"rxRequests,omitempty"` + RxTimeout int32 `protobuf:"varint,6,opt,name=rxTimeout,proto3" json:"rxTimeout,omitempty"` + PayloadMinBytes int32 `protobuf:"varint,7,opt,name=payloadMinBytes,proto3" json:"payloadMinBytes,omitempty"` + PayloadMaxBytes int32 `protobuf:"varint,8,opt,name=payloadMaxBytes,proto3" json:"payloadMaxBytes,omitempty"` + LatencyFrequency int32 `protobuf:"varint,9,opt,name=latencyFrequency,proto3" json:"latencyFrequency,omitempty"` + TxBlockType string `protobuf:"bytes,10,opt,name=txBlockType,proto3" json:"txBlockType,omitempty"` + RxBlockType string `protobuf:"bytes,11,opt,name=rxBlockType,proto3" json:"rxBlockType,omitempty"` + RxSeqBlockSize int32 `protobuf:"varint,12,opt,name=rxSeqBlockSize,proto3" json:"rxSeqBlockSize,omitempty"` + RxPacing string `protobuf:"bytes,13,opt,name=rxPacing,proto3" json:"rxPacing,omitempty"` + RxMaxJitter string `protobuf:"bytes,14,opt,name=rxMaxJitter,proto3" json:"rxMaxJitter,omitempty"` } -func (m *Test) Reset() { *m = Test{} } -func (m *Test) String() string { return proto.CompactTextString(m) } -func (*Test) ProtoMessage() {} +func (x *Test) Reset() { + *x = Test{} + if protoimpl.UnsafeEnabled { + mi := &file_loop3_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Test) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Test) ProtoMessage() {} + +func (x *Test) ProtoReflect() protoreflect.Message { + mi := &file_loop3_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Test.ProtoReflect.Descriptor instead. func (*Test) Descriptor() ([]byte, []int) { - return fileDescriptor_fb557b01f1ee4776, []int{0} + return file_loop3_proto_rawDescGZIP(), []int{0} } -func (m *Test) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Test.Unmarshal(m, b) -} -func (m *Test) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Test.Marshal(b, m, deterministic) -} -func (m *Test) XXX_Merge(src proto.Message) { - xxx_messageInfo_Test.Merge(m, src) -} -func (m *Test) XXX_Size() int { - return xxx_messageInfo_Test.Size(m) -} -func (m *Test) XXX_DiscardUnknown() { - xxx_messageInfo_Test.DiscardUnknown(m) -} - -var xxx_messageInfo_Test proto.InternalMessageInfo - -func (m *Test) GetName() string { - if m != nil { - return m.Name +func (x *Test) GetName() string { + if x != nil { + return x.Name } return "" } -func (m *Test) GetTxRequests() int32 { - if m != nil { - return m.TxRequests +func (x *Test) GetTxRequests() int32 { + if x != nil { + return x.TxRequests } return 0 } -func (m *Test) GetTxPacing() int32 { - if m != nil { - return m.TxPacing +func (x *Test) GetTxPacing() int32 { + if x != nil { + return x.TxPacing } return 0 } -func (m *Test) GetTxMaxJitter() int32 { - if m != nil { - return m.TxMaxJitter +func (x *Test) GetTxMaxJitter() int32 { + if x != nil { + return x.TxMaxJitter } return 0 } -func (m *Test) GetRxRequests() int32 { - if m != nil { - return m.RxRequests +func (x *Test) GetRxRequests() int32 { + if x != nil { + return x.RxRequests } return 0 } -func (m *Test) GetRxTimeout() int32 { - if m != nil { - return m.RxTimeout +func (x *Test) GetRxTimeout() int32 { + if x != nil { + return x.RxTimeout } return 0 } -func (m *Test) GetPayloadMinBytes() int32 { - if m != nil { - return m.PayloadMinBytes +func (x *Test) GetPayloadMinBytes() int32 { + if x != nil { + return x.PayloadMinBytes } return 0 } -func (m *Test) GetPayloadMaxBytes() int32 { - if m != nil { - return m.PayloadMaxBytes +func (x *Test) GetPayloadMaxBytes() int32 { + if x != nil { + return x.PayloadMaxBytes } return 0 } -func (m *Test) GetLatencyFrequency() int32 { - if m != nil { - return m.LatencyFrequency +func (x *Test) GetLatencyFrequency() int32 { + if x != nil { + return x.LatencyFrequency } return 0 } -func (m *Test) GetTxBlockType() string { - if m != nil { - return m.TxBlockType +func (x *Test) GetTxBlockType() string { + if x != nil { + return x.TxBlockType } return "" } -func (m *Test) GetRxBlockType() string { - if m != nil { - return m.RxBlockType +func (x *Test) GetRxBlockType() string { + if x != nil { + return x.RxBlockType } return "" } -func (m *Test) GetRxSeqBlockSize() int32 { - if m != nil { - return m.RxSeqBlockSize +func (x *Test) GetRxSeqBlockSize() int32 { + if x != nil { + return x.RxSeqBlockSize } return 0 } -func init() { - proto.RegisterType((*Test)(nil), "loop3.pb.Test") +func (x *Test) GetRxPacing() string { + if x != nil { + return x.RxPacing + } + return "" } -func init() { - proto.RegisterFile("loop3.proto", fileDescriptor_fb557b01f1ee4776) +func (x *Test) GetRxMaxJitter() string { + if x != nil { + return x.RxMaxJitter + } + return "" } -var fileDescriptor_fb557b01f1ee4776 = []byte{ - // 261 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x91, 0xc1, 0x4a, 0xf3, 0x40, - 0x10, 0xc7, 0xe9, 0xd7, 0xb4, 0x5f, 0x32, 0x11, 0x95, 0x39, 0x2d, 0x22, 0x52, 0x3c, 0x48, 0xf1, - 0xe0, 0xa5, 0x6f, 0xd0, 0x83, 0x07, 0xa1, 0x20, 0x69, 0x5e, 0x60, 0x1b, 0x07, 0x59, 0x4c, 0xb3, - 0xe9, 0x66, 0x0a, 0x1b, 0x1f, 0xc7, 0x27, 0x35, 0x99, 0x14, 0xb3, 0xd6, 0xdb, 0xcc, 0xef, 0xff, - 0xe3, 0x9f, 0xec, 0x2e, 0xa4, 0xa5, 0xb5, 0xf5, 0xea, 0xa9, 0x76, 0x96, 0x2d, 0xc6, 0xa7, 0x65, - 0x77, 0xff, 0x35, 0x85, 0x28, 0xa7, 0x86, 0x11, 0x21, 0xaa, 0xf4, 0x9e, 0xd4, 0x64, 0x31, 0x59, - 0x26, 0x99, 0xcc, 0x78, 0x07, 0xc0, 0x3e, 0xa3, 0xc3, 0xb1, 0x13, 0x1a, 0xf5, 0xaf, 0x4b, 0x66, - 0x59, 0x40, 0xf0, 0x06, 0x62, 0xf6, 0xaf, 0xba, 0x30, 0xd5, 0xbb, 0x9a, 0x4a, 0xfa, 0xb3, 0xe3, - 0x02, 0x52, 0xf6, 0x1b, 0xed, 0x5f, 0x0c, 0x33, 0x39, 0x15, 0x49, 0x1c, 0xa2, 0xbe, 0xdd, 0x8d, - 0xed, 0xb3, 0xa1, 0x7d, 0x24, 0x78, 0x0b, 0x89, 0xf3, 0xb9, 0xd9, 0x93, 0x3d, 0xb2, 0x9a, 0x4b, - 0x3c, 0x02, 0x5c, 0xc2, 0x55, 0xad, 0xdb, 0xd2, 0xea, 0xb7, 0x8d, 0xa9, 0xd6, 0x2d, 0x53, 0xa3, - 0xfe, 0x8b, 0x73, 0x8e, 0x43, 0x53, 0xfb, 0xc1, 0x8c, 0x7f, 0x9b, 0x27, 0x8c, 0x8f, 0x70, 0x5d, - 0x6a, 0xa6, 0xaa, 0x68, 0x9f, 0x5d, 0xff, 0x17, 0xdd, 0xa0, 0x12, 0x51, 0xff, 0xf0, 0xe1, 0x7c, - 0xeb, 0xd2, 0x16, 0x1f, 0x79, 0x5b, 0x93, 0x02, 0xb9, 0xb6, 0x10, 0xf5, 0x86, 0x0b, 0x8c, 0x74, - 0x30, 0x02, 0x84, 0x0f, 0x70, 0xe9, 0xfc, 0x96, 0x0e, 0x42, 0xb6, 0xe6, 0x93, 0xd4, 0x85, 0x7c, - 0xed, 0x8c, 0xee, 0xe6, 0xf2, 0x6a, 0xab, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5a, 0x01, 0xaf, - 0xf2, 0xc4, 0x01, 0x00, 0x00, +var File_loop3_proto protoreflect.FileDescriptor + +var file_loop3_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x6c, 0x6f, 0x6f, 0x70, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x7a, + 0x69, 0x74, 0x69, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x33, 0x2e, 0x70, 0x62, 0x22, 0xe0, 0x03, 0x0a, + 0x04, 0x54, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x78, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, + 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x78, 0x50, + 0x61, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x74, 0x78, 0x50, + 0x61, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x78, 0x4d, 0x61, 0x78, 0x4a, 0x69, + 0x74, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x74, 0x78, 0x4d, 0x61, + 0x78, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x78, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x72, 0x78, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x78, 0x54, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x72, 0x78, 0x54, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x4d, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4d, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x28, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4d, 0x61, 0x78, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x4d, 0x61, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x74, + 0x65, 0x6e, 0x63, 0x79, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x10, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x46, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x78, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x78, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x78, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x78, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x78, 0x53, + 0x65, 0x71, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x0e, 0x72, 0x78, 0x53, 0x65, 0x71, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x78, 0x50, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x78, 0x50, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x20, 0x0a, + 0x0b, 0x72, 0x78, 0x4d, 0x61, 0x78, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x72, 0x78, 0x4d, 0x61, 0x78, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x42, + 0x44, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, + 0x65, 0x6e, 0x7a, 0x69, 0x74, 0x69, 0x2f, 0x7a, 0x69, 0x74, 0x69, 0x2f, 0x7a, 0x69, 0x74, 0x69, + 0x2d, 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x75, 0x62, + 0x63, 0x6d, 0x64, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x33, 0x2f, 0x70, 0x62, 0x2f, 0x6c, 0x6f, 0x6f, + 0x70, 0x33, 0x5f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_loop3_proto_rawDescOnce sync.Once + file_loop3_proto_rawDescData = file_loop3_proto_rawDesc +) + +func file_loop3_proto_rawDescGZIP() []byte { + file_loop3_proto_rawDescOnce.Do(func() { + file_loop3_proto_rawDescData = protoimpl.X.CompressGZIP(file_loop3_proto_rawDescData) + }) + return file_loop3_proto_rawDescData +} + +var file_loop3_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_loop3_proto_goTypes = []interface{}{ + (*Test)(nil), // 0: ziti.loop3.pb.Test +} +var file_loop3_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_loop3_proto_init() } +func file_loop3_proto_init() { + if File_loop3_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_loop3_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Test); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_loop3_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_loop3_proto_goTypes, + DependencyIndexes: file_loop3_proto_depIdxs, + MessageInfos: file_loop3_proto_msgTypes, + }.Build() + File_loop3_proto = out.File + file_loop3_proto_rawDesc = nil + file_loop3_proto_goTypes = nil + file_loop3_proto_depIdxs = nil } diff --git a/ziti-fabric-test/subcmd/loop3/pb/loop3.proto b/ziti-fabric-test/subcmd/loop3/pb/loop3.proto index 75c74373f..6b7a9d07d 100644 --- a/ziti-fabric-test/subcmd/loop3/pb/loop3.proto +++ b/ziti-fabric-test/subcmd/loop3/pb/loop3.proto @@ -1,18 +1,21 @@ syntax = "proto3"; -package loop3.pb; +package ziti.loop3.pb; +option go_package = "github.com/openziti/ziti/ziti-fabric-test/subcmd/loop3/pb/loop3_pb"; message Test { - string name = 1; - int32 txRequests = 2; - int32 txPacing = 3; - int32 txMaxJitter = 4; - int32 rxRequests = 5; - int32 rxTimeout = 6; - int32 payloadMinBytes = 7; - int32 payloadMaxBytes = 8; - int32 latencyFrequency = 9; - string txBlockType = 10; - string rxBlockType = 11; - int32 rxSeqBlockSize = 12; + string name = 1; + int32 txRequests = 2; + int32 txPacing = 3; + int32 txMaxJitter = 4; + int32 rxRequests = 5; + int32 rxTimeout = 6; + int32 payloadMinBytes = 7; + int32 payloadMaxBytes = 8; + int32 latencyFrequency = 9; + string txBlockType = 10; + string rxBlockType = 11; + int32 rxSeqBlockSize = 12; + string rxPacing = 13; + string rxMaxJitter = 14; } \ No newline at end of file diff --git a/ziti-fabric-test/subcmd/loop3/protocol.go b/ziti-fabric-test/subcmd/loop3/protocol.go index fc0569858..6be1c246a 100644 --- a/ziti-fabric-test/subcmd/loop3/protocol.go +++ b/ziti-fabric-test/subcmd/loop3/protocol.go @@ -32,16 +32,18 @@ import ( ) type protocol struct { - test *loop3_pb.Test - blocks chan Block - rxSequence uint64 - peer io.ReadWriteCloser - rxBlocks chan Block - txCount int32 - rxCount int32 - lastRx int64 - latencies chan *time.Time - errors chan error + test *loop3_pb.Test + blocks chan Block + rxSequence uint64 + rxPacing time.Duration + rxMaxJitter time.Duration + peer io.ReadWriteCloser + rxBlocks chan Block + txCount int32 + rxCount int32 + lastRx int64 + latencies chan *time.Time + errors chan error } var MagicHeader = []byte{0xCA, 0xFE, 0xF0, 0x0D} @@ -84,6 +86,18 @@ func (p *protocol) run(test *loop3_pb.Test) error { panic(errors.Errorf("unknown rx block type %v", test.RxBlockType)) } + rxPacing, err := time.ParseDuration(p.test.RxPacing) + if err != nil { + panic(err) + } + p.rxPacing = rxPacing + + rxMaxJitter, err := time.ParseDuration(p.test.RxMaxJitter) + if err != nil { + panic(err) + } + p.rxMaxJitter = rxMaxJitter + rxerDone := make(chan bool) go p.rxer(rxerDone, rxBlock) if p.test.RxRequests > 0 { @@ -155,6 +169,7 @@ func (p *protocol) rxer(done chan bool, rxBlock func() (Block, error)) { defer func() { done <- true }() defer log.Debug("complete") + lastRx := time.Now() for p.rxCount < p.test.RxRequests { block, err := rxBlock() if err != nil { @@ -166,6 +181,22 @@ func (p *protocol) rxer(done chan bool, rxBlock func() (Block, error)) { atomic.AddInt32(&p.rxCount, 1) atomic.StoreInt64(&p.lastRx, info.NowInMilliseconds()) p.rxBlocks <- block + + if p.rxPacing > 0 { + jitter := time.Duration(0) + if p.rxMaxJitter > 0 { + jitter = time.Duration(rand.Intn(int(p.rxMaxJitter))) + } + + now := time.Now() + nextRx := lastRx.Add(p.rxPacing + jitter) + if nextRx.After(now) { + time.Sleep(nextRx.Sub(now)) + lastRx = nextRx + } else { + lastRx = now + } + } } close(p.rxBlocks) diff --git a/ziti-fabric-test/subcmd/loop3/scenario.go b/ziti-fabric-test/subcmd/loop3/scenario.go index 0099df316..774fcdaf5 100644 --- a/ziti-fabric-test/subcmd/loop3/scenario.go +++ b/ziti-fabric-test/subcmd/loop3/scenario.go @@ -37,14 +37,16 @@ type Workload struct { } type Test struct { - TxRequests int32 `yaml:"txRequests"` - TxPacing int32 `yaml:"txPacing"` - TxMaxJitter int32 `yaml:"txMaxJitter"` - RxTimeout int32 `yaml:"rxTimeout"` - PayloadMinBytes int32 `yaml:"payloadMinBytes"` - PayloadMaxBytes int32 `yaml:"payloadMaxBytes"` - LatencyFrequency int32 `yaml:"latencyFrequency"` - BlockType string `yaml:"blockType"` + TxRequests int32 `yaml:"txRequests"` + TxPacing int32 `yaml:"txPacing"` + TxMaxJitter int32 `yaml:"txMaxJitter"` + RxTimeout int32 `yaml:"rxTimeout"` + RxPacing time.Duration `yaml:"rxPacing"` + RxMaxJitter time.Duration `yaml:"rxMaxJitter"` + PayloadMinBytes int32 `yaml:"payloadMinBytes"` + PayloadMaxBytes int32 `yaml:"payloadMaxBytes"` + LatencyFrequency int32 `yaml:"latencyFrequency"` + BlockType string `yaml:"blockType"` } func (workload *Workload) GetTests() (*loop3_pb.Test, *loop3_pb.Test) { @@ -54,6 +56,8 @@ func (workload *Workload) GetTests() (*loop3_pb.Test, *loop3_pb.Test) { TxPacing: workload.Dialer.TxPacing, TxMaxJitter: workload.Dialer.TxMaxJitter, RxRequests: workload.Listener.TxRequests, + RxPacing: workload.Dialer.RxPacing.String(), + RxMaxJitter: workload.Dialer.RxMaxJitter.String(), RxTimeout: workload.Dialer.RxTimeout, RxSeqBlockSize: workload.Listener.PayloadMinBytes, PayloadMinBytes: workload.Dialer.PayloadMinBytes, @@ -69,6 +73,8 @@ func (workload *Workload) GetTests() (*loop3_pb.Test, *loop3_pb.Test) { TxPacing: workload.Listener.TxPacing, TxMaxJitter: workload.Listener.TxMaxJitter, RxRequests: workload.Dialer.TxRequests, + RxPacing: workload.Listener.RxPacing.String(), + RxMaxJitter: workload.Listener.RxMaxJitter.String(), RxTimeout: workload.Listener.RxTimeout, RxSeqBlockSize: workload.Dialer.PayloadMinBytes, PayloadMinBytes: workload.Listener.PayloadMinBytes, diff --git a/ziti/cmd/ziti/cmd/cmd.go b/ziti/cmd/ziti/cmd/cmd.go index d8e361f5d..975928744 100644 --- a/ziti/cmd/ziti/cmd/cmd.go +++ b/ziti/cmd/ziti/cmd/cmd.go @@ -20,7 +20,9 @@ import ( goflag "flag" "fmt" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/demo" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/fabric" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/tutorial" "io" "os" "path/filepath" @@ -136,6 +138,8 @@ func NewCmdRoot(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Comm pkiCommands := NewCmdPKI(f, out, err) fabricCommand := fabric.NewFabricCmd(p) edgeCommand := edge.NewCmdEdge(f, out, err) + tutorialCmd := tutorial.NewTutorialCmd(p) + demoCmd := demo.NewDemoCmd(p) logFilter := NewCmdLogFormat(f, out, err) unwrapIdentityFileCommand := NewUnwrapIdentityFileCommand(f, out, err) @@ -181,6 +185,13 @@ func NewCmdRoot(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Comm logFilter, }, }, + { + Message: "Learning Ziti", + Commands: []*cobra.Command{ + demoCmd, + tutorialCmd, + }, + }, } groups.Add(cmd) diff --git a/ziti/cmd/ziti/cmd/demo/echo_server.go b/ziti/cmd/ziti/cmd/demo/echo_server.go new file mode 100644 index 000000000..575652707 --- /dev/null +++ b/ziti/cmd/ziti/cmd/demo/echo_server.go @@ -0,0 +1,166 @@ +/* + 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 demo + +import ( + "errors" + "fmt" + "github.com/michaelquigley/pfxlog" + "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "io" + "net" +) + +type echoServer struct { + port uint16 + verbose bool + logFormatter string + configFile string + service string +} + +func newEchoServerCmd(common.OptionsProvider) *cobra.Command { + server := &echoServer{} + + cmd := &cobra.Command{ + Use: "echo-server", + Short: "Runs a simple network echo service", + Args: cobra.ExactArgs(0), + Run: server.run, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().Uint16VarP(&server.port, "port", "p", 0, "Specify the port to listen on. If not specified the TCP listener won't be started") + cmd.Flags().BoolVarP(&server.verbose, "verbose", "v", false, "Enable verbose logging") + cmd.Flags().StringVar(&server.logFormatter, "log-formatter", "", "Specify log formatter [json|pfxlog|text]") + cmd.Flags().StringVarP(&server.configFile, "identity", "i", "", "Specify the Ziti identity to use. If not specified the Ziti listener won't be started") + cmd.Flags().StringVarP(&server.service, "service", "s", "echo", "Ziti service to bind. Defaults to 'echo'") + cmd.Flags().SetInterspersed(true) + + return cmd +} + +func (self *echoServer) initLogging() { + logLevel := logrus.InfoLevel + if self.verbose { + logLevel = logrus.DebugLevel + } + + options := pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti/").NoColor() + pfxlog.GlobalInit(logLevel, options) + + switch self.logFormatter { + case "pfxlog": + pfxlog.SetFormatter(pfxlog.NewFormatter(pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti/").StartingToday())) + case "json": + pfxlog.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "2006-01-02T15:04:05.000Z"}) + case "text": + pfxlog.SetFormatter(&logrus.TextFormatter{}) + default: + // let logrus do its own thing + } +} + +func (self *echoServer) run(*cobra.Command, []string) { + self.initLogging() + + log := pfxlog.Logger() + + if self.port == 0 && self.configFile == "" { + log.Fatalf("No port specified and no ziti identity specified. Not starting either listener, so nothing to do. exiting.") + } + + if self.port > 0 { + addr := fmt.Sprintf("0.0.0.0:%v", self.port) + log.Infof("tcp: starting listener on address [%v]", addr) + listener, err := net.Listen("tcp", addr) + if err != nil { + log.WithError(err).Fatalf("unable to start TCP listener on addr [%v]", addr) + } + + go self.accept("tcp", listener) + } + + if self.configFile != "" { + zitiConfig, err := config.NewFromFile(self.configFile) + if err != nil { + log.WithError(err).Fatalf("ziti: unable to load ziti identity from [%v]", self.configFile) + } + + zitiContext := ziti.NewContextWithConfig(zitiConfig) + + log.Infof("ziti: starting listener for service (%v)", self.service) + listener, err := zitiContext.Listen(self.service) + if err != nil { + log.WithError(err).Fatalf("ziti: failed to host service [%v]", self.service) + } + + go self.accept("ziti", listener) + } + + waitC := make(chan struct{}) + <-waitC +} + +func (self *echoServer) accept(connType string, listener net.Listener) { + log := pfxlog.Logger() + + for { + conn, err := listener.Accept() + if err != nil { + panic(err) + } + log.Infof("%v: connection received: %v", connType, conn) + go self.echo(connType, conn) + } +} + +func (self *echoServer) echo(connType string, conn io.ReadWriteCloser) { + log := pfxlog.Logger() + + defer func() { + if err := conn.Close(); err != nil { + log.WithError(err).Errorf("%v: Error while closing connection", connType) + } + log.Infof("%v: connection closed", connType) + }() + + for { + buf := make([]byte, 1024) + n, err := conn.Read(buf) + if err != nil { + if errors.Is(err, io.EOF) { + log.Infof("%v: received eof, closing connection", connType) + } else { + log.WithError(err).Errorf("%v: error while reading", connType) + } + break + } + log.Infof("%v: read %v bytes", connType, n) + writeBuf := buf[:n] + if _, err := conn.Write(writeBuf); err != nil { + log.WithError(err).Errorf("%v: error while writing", connType) + break + } + log.Infof("%v: wrote %v bytes", connType, n) + } +} diff --git a/ziti/cmd/ziti/cmd/demo/root.go b/ziti/cmd/ziti/cmd/demo/root.go new file mode 100644 index 000000000..6f1c2aba8 --- /dev/null +++ b/ziti/cmd/ziti/cmd/demo/root.go @@ -0,0 +1,41 @@ +/* + 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 demo + +import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/spf13/cobra" +) + +func NewDemoCmd(p common.OptionsProvider) *cobra.Command { + cmd := &cobra.Command{ + Use: "demo", + Short: "Demos and examples for learning about Ziti", + Run: func(cmd *cobra.Command, args []string) { + err := cmd.Help() + helpers.CheckErr(err) + }, + } + + cmd.AddCommand(newEchoServerCmd(p)) + cmd.AddCommand(newZcatCmd(p)) + cmd.AddCommand(newSimpleEchoSdkHostedCmd(p)) + cmd.AddCommand(newSimpleEchoRouterTunnelerHostedCmd(p)) + + return cmd +} diff --git a/ziti/cmd/ziti/cmd/demo/setup-scripts/simple-echo-router-tunneler-hosted.md b/ziti/cmd/ziti/cmd/demo/setup-scripts/simple-echo-router-tunneler-hosted.md new file mode 100644 index 000000000..6aa49f410 --- /dev/null +++ b/ziti/cmd/ziti/cmd/demo/setup-scripts/simple-echo-router-tunneler-hosted.md @@ -0,0 +1,93 @@ +# Purpose + +This script sets up an echo service which is hosted by a router-embedded tunneler and +is accessed by another sdk application. + +# Prerequisites + +You need at least one controller and an edge router running. for this to work. +You can use the quick-start script found [here](https://github.com/openziti/ziti/tree/release-next/quickstart). + +# Setup + +First, ensure we're logged into the controller. + +```action:ziti-login allowRetry=true +ziti edge login +``` + +```action:keep-session-alive interval=1m +If your session times out you can run ziti edge login again. +``` + +Remove any entities from previous runs. + +```action:ziti +ziti edge delete service echo +ziti edge delete config echo-host +ziti edge delete identities zcat echo-host +ziti edge delete service-policies echo-dial echo-bind +ziti edge delete edge-router-policies echo +ziti edge delete service-edge-router-policies echo +``` + +Create the echo-host config + +```action:ziti-create-config name=echo-host type=host.v2 +{ + "terminators" : [ + { + "address" : "localhost", + "port" : 1234, + "protocol" : "tcp" + } + ] +} +``` + +Create the echo service + +```action:ziti +ziti edge create service echo -c echo-host +``` + +Select an edge router to host this service on + +```action:select-edge-router +Pick the name of an edge router to use. It will be referenced in this tutorial as ${edgeRouterName} +``` + +Update the select edge router with the `echo-host` attribute so it gets tied into the policies + +```action:ziti templatize=true +ziti edge update identity ${edgeRouterName} -a echo-host +``` + +Create and enroll the client app identity + +```action:ziti +ziti edge create identity service zcat -a echo,echo-client -o zcat.jwt +ziti edge enroll --rm zcat.jwt +``` + +Configure policies + +```action:ziti +ziti edge create service-policy echo-dial Dial --service-roles @echo --identity-roles #echo-client +ziti edge create service-policy echo-bind Bind --service-roles @echo --identity-roles #echo-host +ziti edge create edge-router-policy echo --identity-roles #echo --edge-router-roles #all +ziti edge create service-edge-router-policy echo --service-roles @echo --edge-router-roles #all +``` + +You should now be to run the echo server with + +``` +ziti demo echo-server -p 1234 +``` + +and +the zcat client using + +``` +ziti demo zcat -i zcat.json ziti:echo +``` diff --git a/ziti/cmd/ziti/cmd/demo/setup-scripts/simple-echo-sdk-hosted.md b/ziti/cmd/ziti/cmd/demo/setup-scripts/simple-echo-sdk-hosted.md new file mode 100644 index 000000000..0e55f7403 --- /dev/null +++ b/ziti/cmd/ziti/cmd/demo/setup-scripts/simple-echo-sdk-hosted.md @@ -0,0 +1,74 @@ +# Purpose + +This script sets up an echo service which is hosted by an SDK application and +is accessed by another sdk application. + +# Prerequisites + +You need at least one controller and an edge router running. for this to work. +You can use the quick-start script found [here](https://github.com/openziti/ziti/tree/release-next/quickstart). + +# Setup + +First, ensure we're logged into the controller. + +```action:ziti-login allowRetry=true +ziti edge login +``` + +```action:keep-session-alive interval=1m +If your session times out you can run ziti edge login again. +``` + +Remove any entities from previous runs. + +```action:ziti +ziti edge delete service echo +ziti edge delete config echo-host +ziti edge delete identities zcat echo-host +ziti edge delete service-policies echo-dial echo-bind +ziti edge delete edge-router-policies echo +ziti edge delete service-edge-router-policies echo +``` + +Create the echo service + +```action:ziti +ziti edge create service echo +``` + +Create and enroll the hosting identity + +```action:ziti +ziti edge create identity service echo-host -a echo,echo-host -o echo-host.jwt +ziti edge enroll --rm echo-host.jwt +``` + +Create and enroll the client app identity + +```action:ziti +ziti edge create identity service zcat -a echo,echo-client -o zcat.jwt +ziti edge enroll --rm zcat.jwt +``` + +Configure policies + +```action:ziti +ziti edge create service-policy echo-dial Dial --service-roles @echo --identity-roles #echo-client +ziti edge create service-policy echo-bind Bind --service-roles @echo --identity-roles #echo-host +ziti edge create edge-router-policy echo --identity-roles #echo --edge-router-roles #all +ziti edge create service-edge-router-policy echo --service-roles @echo --edge-router-roles #all +``` + +You should now be to run the echo server with + +``` +ziti demo echo-server -i echo-host.json +``` + +and +the zcat client using + +``` +ziti demo zcat -i zcat.json ziti:echo +``` diff --git a/ziti/cmd/ziti/cmd/demo/setup-simple-router-tunneler-hosted-service.go b/ziti/cmd/ziti/cmd/demo/setup-simple-router-tunneler-hosted-service.go new file mode 100644 index 000000000..827d9972b --- /dev/null +++ b/ziti/cmd/ziti/cmd/demo/setup-simple-router-tunneler-hosted-service.go @@ -0,0 +1,86 @@ +/* + 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 demo + +import ( + _ "embed" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + tutorial2 "github.com/openziti/ziti/ziti/cmd/ziti/cmd/tutorial" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/tutorial/actions" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "github.com/spf13/cobra" + "time" +) + +//go:embed setup-scripts/simple-echo-router-tunneler-hosted.md +var simpleEchoRouterTunnelerHostedScriptSource []byte + +type simpleEchoRouterTunnelerHosted struct { + api.Options + tutorial2.TutorialOptions + interactive bool +} + +func newSimpleEchoRouterTunnelerHostedCmd(p common.OptionsProvider) *cobra.Command { + options := &simpleEchoRouterTunnelerHosted{ + Options: api.Options{ + CommonOptions: p(), + }, + } + + cmd := &cobra.Command{ + Use: "setup-simple-echo-router-tunneler-hosted", + Short: "Walks you through configuration for a simple echo service, hosted by a router-embedded tunneler", + Args: cobra.ExactArgs(0), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := options.run() + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVar(&options.ControllerUrl, "controller-url", "", "The Ziti controller URL to use") + cmd.Flags().StringVarP(&options.Username, "username", "u", "", "The Ziti controller username to use") + cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The Ziti controller password to use") + cmd.Flags().DurationVar(&options.NewlinePause, "newline-pause", time.Millisecond*10, "How long to pause between lines when scrolling") + cmd.Flags().BoolVar(&options.interactive, "interactive", false, "Interactive mode, waiting for user input") + options.AddCommonFlags(cmd) + + return cmd +} + +func (self *simpleEchoRouterTunnelerHosted) run() error { + t := tutorial.NewRunner() + t.NewLinePause = self.NewlinePause + t.AssumeDefault = !self.interactive + + t.RegisterActionHandler("ziti", &actions.ZitiRunnerAction{}) + t.RegisterActionHandler("ziti-login", &actions.ZitiEnsureLoggedIn{ + LoginParams: &self.TutorialOptions, + }) + t.RegisterActionHandler("keep-session-alive", &actions.KeepSessionAliveAction{}) + t.RegisterActionHandler("ziti-create-config", &actions.ZitiCreateConfigAction{}) + t.RegisterActionHandler("select-edge-router", &actions.SelectEdgeRouterAction{}) + + return t.Run(simpleEchoRouterTunnelerHostedScriptSource) +} diff --git a/ziti/cmd/ziti/cmd/demo/setup-simple-sdk-service.go b/ziti/cmd/ziti/cmd/demo/setup-simple-sdk-service.go new file mode 100644 index 000000000..88f3fa325 --- /dev/null +++ b/ziti/cmd/ziti/cmd/demo/setup-simple-sdk-service.go @@ -0,0 +1,85 @@ +/* + 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 demo + +import ( + _ "embed" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + tutorial2 "github.com/openziti/ziti/ziti/cmd/ziti/cmd/tutorial" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/tutorial/actions" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "github.com/spf13/cobra" + "time" +) + +//go:embed setup-scripts/simple-echo-sdk-hosted.md +var simpleEchoSdkHostedScriptSource []byte + +type simpleEchoSdkHosted struct { + api.Options + tutorial2.TutorialOptions + interactive bool +} + +func newSimpleEchoSdkHostedCmd(p common.OptionsProvider) *cobra.Command { + options := &simpleEchoSdkHosted{ + Options: api.Options{ + CommonOptions: p(), + }, + } + + cmd := &cobra.Command{ + Use: "setup-simple-echo-sdk-hosted", + Short: "Walks you through configuration for a simple sdk hosted sdk service", + Args: cobra.ExactArgs(0), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := options.run() + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVar(&options.ControllerUrl, "controller-url", "", "The Ziti controller URL to use") + cmd.Flags().StringVarP(&options.Username, "username", "u", "", "The Ziti controller username to use") + cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The Ziti controller password to use") + cmd.Flags().DurationVar(&options.NewlinePause, "newline-pause", time.Millisecond*10, "How long to pause between lines when scrolling") + cmd.Flags().BoolVar(&options.interactive, "interactive", false, "Interactive mode, waiting for user input") + options.AddCommonFlags(cmd) + + return cmd +} + +func (self *simpleEchoSdkHosted) run() error { + t := tutorial.NewRunner() + t.NewLinePause = self.NewlinePause + t.AssumeDefault = !self.interactive + + t.RegisterActionHandler("ziti", &actions.ZitiRunnerAction{}) + t.RegisterActionHandler("ziti-login", &actions.ZitiEnsureLoggedIn{ + LoginParams: &self.TutorialOptions, + }) + t.RegisterActionHandler("keep-session-alive", &actions.KeepSessionAliveAction{}) + t.RegisterActionHandler("select-edge-router", &actions.SelectEdgeRouterAction{}) + + return t.Run(simpleEchoSdkHostedScriptSource) +} diff --git a/ziti/cmd/ziti/cmd/demo/zcat.go b/ziti/cmd/ziti/cmd/demo/zcat.go new file mode 100644 index 000000000..7e13bca70 --- /dev/null +++ b/ziti/cmd/ziti/cmd/demo/zcat.go @@ -0,0 +1,128 @@ +/* + 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 demo + +import ( + "github.com/michaelquigley/pfxlog" + "github.com/openziti/foundation/util/info" + "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "io" + "net" + "os" + "strings" +) + +type zcat struct { + verbose bool + logFormatter string + configFile string +} + +func newZcatCmd(common.OptionsProvider) *cobra.Command { + server := &zcat{} + + cmd := &cobra.Command{ + Use: "zcat ", + Example: "ziti demo zcat tcp:localhost:1234 or ziti demo zcat -i zcat.json ziti:echo", + Short: "A simple network cat facility which can run over tcp or ziti", + Args: cobra.ExactArgs(1), + Run: server.run, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().BoolVarP(&server.verbose, "verbose", "v", false, "Enable verbose logging") + cmd.Flags().StringVar(&server.logFormatter, "log-formatter", "", "Specify log formatter [json|pfxlog|text]") + cmd.Flags().StringVarP(&server.configFile, "identity", "i", "", "Specify the Ziti identity to use. If not specified the Ziti listener won't be started") + cmd.Flags().SetInterspersed(true) + + return cmd +} + +func (self *zcat) initLogging() { + logLevel := logrus.InfoLevel + if self.verbose { + logLevel = logrus.DebugLevel + } + + options := pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti/").NoColor() + pfxlog.GlobalInit(logLevel, options) + + switch self.logFormatter { + case "pfxlog": + pfxlog.SetFormatter(pfxlog.NewFormatter(pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti/").StartingToday())) + case "json": + pfxlog.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "2006-01-02T15:04:05.000Z"}) + case "text": + pfxlog.SetFormatter(&logrus.TextFormatter{}) + default: + // let logrus do its own thing + } +} + +func (self *zcat) run(_ *cobra.Command, args []string) { + self.initLogging() + + log := pfxlog.Logger() + + parts := strings.Split(args[0], ":") + if len(parts) < 2 { + log.Fatalf("destination %v is invalid. destination must be of the form network:address", args[0]) + } + network := parts[0] + addr := strings.Join(parts[1:], ":") + + var conn net.Conn + var err error + + log.Debugf("dialing %v:%v", network, addr) + if network == "tcp" || network == "udp" { + conn, err = net.Dial(network, addr) + } else if network == "ziti" { + zitiConfig, cfgErr := config.NewFromFile(self.configFile) + if cfgErr != nil { + log.WithError(cfgErr).Fatalf("unable to load ziti identity from [%v]", self.configFile) + } + + zitiContext := ziti.NewContextWithConfig(zitiConfig) + conn, err = zitiContext.Dial(addr) + } else { + log.Fatalf("invalid network '%v'. valid values are ['ziti', 'tcp', 'udp']", network) + } + + if err != nil { + log.WithError(err).Fatalf("unable to dial %v:%v", network, addr) + } + + log.Debugf("connected to %v:%v", network, addr) + + go self.copy(conn, os.Stdin) + self.copy(os.Stdout, conn) +} + +func (self *zcat) copy(writer io.Writer, reader io.Reader) { + buf := make([]byte, info.MaxUdpPacketSize) + bytesCopied, err := io.CopyBuffer(writer, reader, buf) + pfxlog.Logger().Debugf("Copied %v bytes", bytesCopied) + if err != nil { + pfxlog.Logger().WithError(err).Error("error while copying bytes") + } +} diff --git a/ziti/cmd/ziti/cmd/edge/delete.go b/ziti/cmd/ziti/cmd/edge/delete.go index e810a9244..48b6f3a4e 100644 --- a/ziti/cmd/ziti/cmd/edge/delete.go +++ b/ziti/cmd/ziti/cmd/edge/delete.go @@ -147,7 +147,7 @@ func runDeleteEntityOfTypeWhere(options *api.Options, entityType string) error { params := url.Values{} params.Add("filter", filter) - children, pageInfo, err := listEntitiesOfType(entityType, params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) + children, pageInfo, err := ListEntitiesOfType(entityType, params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) if err != nil { return err } diff --git a/ziti/cmd/ziti/cmd/edge/list.go b/ziti/cmd/ziti/cmd/edge/list.go index 494ee5b65..36a0c8d1c 100644 --- a/ziti/cmd/ziti/cmd/edge/list.go +++ b/ziti/cmd/ziti/cmd/edge/list.go @@ -318,30 +318,30 @@ func newSubListCmdForEntityType(entityType string, subType string, outputF outpu return cmd } -// listEntitiesOfType queries the Ziti Controller for entities of the given type +// ListEntitiesOfType queries the Ziti Controller for entities of the given type func listEntitiesWithOptions(entityType string, options *api.Options) ([]*gabs.Container, *paging, error) { params := url.Values{} if len(options.Args) > 0 { params.Add("filter", options.Args[0]) } - return listEntitiesOfType(entityType, params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) + return ListEntitiesOfType(entityType, params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) } -func listEntitiesWithFilter(entityType string, filter string) ([]*gabs.Container, *paging, error) { +func ListEntitiesWithFilter(entityType string, filter string) ([]*gabs.Container, *paging, error) { params := url.Values{} params.Add("filter", filter) - return listEntitiesOfType(entityType, params, false, nil, 5, false) + return ListEntitiesOfType(entityType, params, false, nil, 5, false) } func filterEntitiesOfType(entityType string, filter string, logJSON bool, out io.Writer, timeout int, verbose bool) ([]*gabs.Container, *paging, error) { params := url.Values{} params.Add("filter", filter) - return listEntitiesOfType(entityType, params, logJSON, out, timeout, verbose) + return ListEntitiesOfType(entityType, params, logJSON, out, timeout, verbose) } -// listEntitiesOfType queries the Ziti Controller for entities of the given type -func listEntitiesOfType(entityType string, params url.Values, logJSON bool, out io.Writer, timeout int, verbose bool) ([]*gabs.Container, *paging, error) { +// ListEntitiesOfType queries the Ziti Controller for entities of the given type +func ListEntitiesOfType(entityType string, params url.Values, logJSON bool, out io.Writer, timeout int, verbose bool) ([]*gabs.Container, *paging, error) { jsonParsed, err := util.EdgeControllerList(entityType, params, logJSON, out, timeout, verbose) if err != nil { @@ -379,7 +379,7 @@ func getPaging(c *gabs.Container) *paging { return pagingInfo } -// listEntitiesOfType queries the Ziti Controller for entities of the given type +// ListEntitiesOfType queries the Ziti Controller for entities of the given type func filterSubEntitiesOfType(entityType, subType, entityId, filter string, o *api.Options) ([]*gabs.Container, *paging, error) { jsonParsed, err := util.EdgeControllerListSubEntities(entityType, subType, entityId, filter, o.OutputJSONResponse, o.Out, o.Timeout, o.Verbose) @@ -405,7 +405,7 @@ func runListEdgeRouters(roleFilters []string, roleSemantic string, options *api. if roleSemantic != "" { params.Add("roleSemantic", roleSemantic) } - children, paging, err := listEntitiesOfType("edge-routers", params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) + children, paging, err := ListEntitiesOfType("edge-routers", params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) if err != nil { return err } @@ -528,7 +528,7 @@ func runListServices(asIdentity string, configTypes []string, roleFilters []stri if roleSemantic != "" { params.Add("roleSemantic", roleSemantic) } - children, pagingInfo, err := listEntitiesOfType("services", params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) + children, pagingInfo, err := ListEntitiesOfType("services", params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) if err != nil { return err } @@ -697,7 +697,7 @@ func runListIdentities(roleFilters []string, roleSemantic string, options *api.O if roleSemantic != "" { params.Add("roleSemantic", roleSemantic) } - children, pagingInfo, err := listEntitiesOfType("identities", params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) + children, pagingInfo, err := ListEntitiesOfType("identities", params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) if err != nil { return err } diff --git a/ziti/cmd/ziti/cmd/edge/root.go b/ziti/cmd/ziti/cmd/edge/root.go index e34cc14ba..662b4a835 100644 --- a/ziti/cmd/ziti/cmd/edge/root.go +++ b/ziti/cmd/ziti/cmd/edge/root.go @@ -18,14 +18,16 @@ package edge import ( "github.com/openziti/ziti/common/enrollment" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" "io" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/spf13/cobra" ) +var ExtraEdgeCommands []func(p common.OptionsProvider) *cobra.Command + // NewCmdEdge creates a command object for the "controller" command func NewCmdEdge(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { cmd := util.NewEmptyParentCmd("edge", "Interact with Ziti Edge Components") @@ -34,7 +36,6 @@ func NewCmdEdge(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comma } func populateEdgeCommands(f cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Command) *cobra.Command { - p := common.NewOptionsProvider(out, errOut) cmd.AddCommand(newCreateCmd(f, out, errOut)) cmd.AddCommand(newDeleteCmd(out, errOut)) cmd.AddCommand(newLoginCmd(out, errOut)) @@ -48,7 +49,12 @@ func populateEdgeCommands(f cmdutil.Factory, out io.Writer, errOut io.Writer, cm cmd.AddCommand(newDbCmd(out, errOut)) cmd.AddCommand(enrollment.NewEnrollCommand()) cmd.AddCommand(newTraceCmd(out, errOut)) - cmd.AddCommand(newTutorialCmd(p)) cmd.AddCommand(newTraceRouteCmd(out, errOut)) + + p := common.NewOptionsProvider(out, errOut) + for _, cmdF := range ExtraEdgeCommands { + cmd.AddCommand(cmdF(p)) + } + return cmd } diff --git a/ziti/cmd/ziti/cmd/edge/tutorial.go b/ziti/cmd/ziti/cmd/edge/tutorial.go deleted file mode 100644 index b0a1272cd..000000000 --- a/ziti/cmd/ziti/cmd/edge/tutorial.go +++ /dev/null @@ -1,426 +0,0 @@ -package edge - -import ( - _ "embed" - "fmt" - "github.com/fatih/color" - "github.com/openziti/foundation/util/term" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "net/url" - "os" - "strconv" - "strings" - "time" -) - -//go:embed tutorials/first-service.md -var firstServiceTutorialSource []byte - -//go:embed tutorial_plain_echo_server.go -var plainEchoServerSource string - -//go:embed tutorial_plain_echo_client.go -var plainEchoClientSource string - -//go:embed tutorial_ziti_echo_client.go -var zitiEchoClientSource string - -//go:embed tutorial_ziti_echo_server.go -var zitiEchoServerSource string - -func newTutorialCmd(p common.OptionsProvider) *cobra.Command { - cmd := &cobra.Command{ - Use: "tutorial", - Short: "Interactive tutorials for learning about Ziti", - Run: func(cmd *cobra.Command, args []string) { - err := cmd.Help() - cmdhelper.CheckErr(err) - }, - } - - cmd.AddCommand(newFirstServiceTutorialCmd(p)) - cmd.AddCommand(newPlainEchoServerCmd(p)) - cmd.AddCommand(newPlainEchoClientCmd(p)) - cmd.AddCommand(newZitiEchoClientCmd(p)) - cmd.AddCommand(newZitiEchoServerCmd(p)) - - return cmd -} - -type tutorialOptions struct { - controllerUrl string - username string - password string - newlinePause time.Duration - assumeDefault bool -} - -type firstServiceTutorialOptions struct { - api.Options - tutorialOptions -} - -func newFirstServiceTutorialCmd(p common.OptionsProvider) *cobra.Command { - options := &firstServiceTutorialOptions{ - Options: api.Options{ - CommonOptions: p(), - }, - } - - cmd := &cobra.Command{ - Use: "first-service", - Short: "Walks you through creating a service, identity and policies", - Args: cobra.ExactArgs(0), - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.run() - cmdhelper.CheckErr(err) - }, - SuggestFor: []string{}, - } - - // allow interspersing positional args and flags - cmd.Flags().SetInterspersed(true) - cmd.Flags().StringVar(&options.controllerUrl, "controller-url", "", "The Ziti controller URL to use") - cmd.Flags().StringVarP(&options.username, "username", "u", "", "The Ziti controller username to use") - cmd.Flags().StringVarP(&options.password, "password", "p", "", "The Ziti controller password to use") - cmd.Flags().DurationVar(&options.newlinePause, "newline-pause", time.Millisecond*10, "How long to pause between lines when scrolling") - cmd.Flags().BoolVar(&options.assumeDefault, "assume-default", false, "Non-interactive mode, assuming default input when user input is required") - options.AddCommonFlags(cmd) - - return cmd -} - -func (self *firstServiceTutorialOptions) run() error { - t := tutorial.NewRunner() - t.NewLinePause = self.newlinePause - t.AssumeDefault = self.assumeDefault - - t.RegisterActionHandler("ziti", &ZitiRunnerAction{}) - t.RegisterActionHandler("ziti-login", &ZitiLoginAction{ - options: &self.tutorialOptions, - }) - t.RegisterActionHandler("keep-session-alive", &KeepSessionAliveAction{}) - t.RegisterActionHandler("select-edge-router", &SelectEdgeRouterAction{}) - - plainEchoServerActions := &PlainEchoServerActions{} - t.RegisterActionHandlerF("run-plain-echo-server", plainEchoServerActions.Start) - t.RegisterActionHandlerF("stop-plain-echo-server", plainEchoServerActions.Stop) - - zitiEchoServerActions := &ZitiEchoServerActions{} - t.RegisterActionHandlerF("run-ziti-echo-server", zitiEchoServerActions.Start) - t.RegisterActionHandlerF("stop-ziti-echo-server", zitiEchoServerActions.Stop) - - showActionHandler := tutorial.NewShowActionHandler() - showActionHandler.Add("tutorial_plain_echo_server.go", plainEchoServerSource) - showActionHandler.Add("tutorial_plain_echo_client.go", plainEchoClientSource) - showActionHandler.Add("tutorial_ziti_echo_client.go", zitiEchoClientSource) - showActionHandler.Add("tutorial_ziti_echo_server.go", zitiEchoServerSource) - t.RegisterActionHandler("show", showActionHandler) - - return t.Run(firstServiceTutorialSource) -} - -type ZitiLoginAction struct { - options *tutorialOptions -} - -func (self *ZitiLoginAction) Execute(ctx *tutorial.ActionContext) error { - cmd := "ziti edge login --ignore-config" - if self.options.controllerUrl != "" { - cmd += " " + self.options.controllerUrl - } - if self.options.username != "" { - cmd += " --username " + self.options.username - } - if self.options.password != "" { - cmd += " --password " + self.options.password - } - ctx.Body = cmd - return (&ZitiRunnerAction{}).Execute(ctx) -} - -type ZitiRunnerAction struct{} - -func (self *ZitiRunnerAction) Execute(ctx *tutorial.ActionContext) error { - if strings.EqualFold("true", ctx.Headers["templatize"]) { - body, err := ctx.Runner.Template(ctx.Body) - if err != nil { - return err - } - ctx.Body = body - } - lines := strings.Split(ctx.Body, "\n") - var cmds [][]string - buf := &strings.Builder{} - buf.WriteString("About to execute:\n\n") - - for _, line := range lines { - line = strings.TrimSpace(line) - if len(line) > 0 { - params := tutorial.ParseArgumentsWithStrings(line) - if params[0] != "ziti" { - return errors.Errorf("invalid parameter for ziti action, must start with 'ziti': %v", ctx.Body) - } - params[0] = line - cmds = append(cmds, params) - ctx.Runner.LeftPadBuilder(buf) - buf.WriteString(" ") - buf.WriteString(color.New(color.Bold).Sprintf(line)) - buf.WriteRune('\n') - } - } - buf.WriteRune('\n') - ctx.Runner.LeftPadBuilder(buf) - buf.WriteString("Continue [Y/N] (default Y): ") - - if !ctx.Runner.AssumeDefault { - tutorial.Continue(buf.String(), true) - } - - fmt.Println("") - c := color.New(color.FgBlue, color.Bold) - - colorStdOut := !strings.EqualFold("false", ctx.Headers["colorStdOut"]) - - allowRetry := strings.EqualFold("true", ctx.Headers["allowRetry"]) - failOk := strings.EqualFold("true", ctx.Headers["failOk"]) - for _, cmd := range cmds { - _, _ = c.Printf("$ %v\n", cmd[0]) - done := false - for !done { - if err := tutorial.Exec(os.Args[0], colorStdOut, cmd[1:]...); err != nil { - if failOk { - return nil - } - if allowRetry { - retry, err2 := tutorial.AskYesNoWithDefault(fmt.Sprintf("operation failed with err: %v. Retry [Y/N] (default Y):", err), true) - if err2 != nil { - fmt.Printf("error while asking about retry: %v\n", err2) - return err - } - if !retry { - return err - } - } else { - return err - } - } else { - done = true - } - } - } - return nil -} - -type KeepSessionAliveAction struct{} - -func (self *KeepSessionAliveAction) Execute(ctx *tutorial.ActionContext) error { - interval := time.Minute - if val, ok := ctx.Headers["interval"]; ok { - if d, err := time.ParseDuration(val); err != nil { - return err - } else { - interval = d - } - } - fmt.Printf("Running session refresh every %v\n", interval) - go func() { - ticker := time.NewTicker(interval) - for { - select { - case <-ticker.C: - _, _, _ = listEntitiesOfType("edge-routers", url.Values{}, false, nil, 10, false) - } - } - }() - return nil -} - -type edgeRouter struct { - id string - name string -} - -type SelectEdgeRouterAction struct{} - -func (self *SelectEdgeRouterAction) Execute(ctx *tutorial.ActionContext) error { - for { - err := self.SelectEdgeRouter(ctx) - if err == nil { - return nil - } - - retry, err2 := tutorial.AskYesNoWithDefault(fmt.Sprintf("Error getting edge router (err=%v). Try again? [Y/N] (default Y): ", err), true) - if err2 != nil { - fmt.Printf("encountered error prompting for input: %v\n", err2) - return err - } - - if !retry { - return err - } - } -} - -func (self *SelectEdgeRouterAction) SelectEdgeRouter(ctx *tutorial.ActionContext) error { - fmt.Println("") - - valid := false - var edgeRouterName string - - for !valid { - children, _, err := listEntitiesWithFilter("edge-routers", "limit none") - if err != nil { - return errors.Wrap(err, "unable to list edge routers") - } - - var ers []*edgeRouter - - if len(children) == 0 { - return errors.New("no edge routers found") - } - - for _, child := range children { - isOnline := child.S("isOnline").Data().(bool) - if isOnline { - id := child.S("id").Data().(string) - name := child.S("name").Data().(string) - ers = append(ers, &edgeRouter{id: id, name: name}) - } - } - - if len(ers) == 0 { - fmt.Println("Error: no online edge routers found. Found these offline edge routers: ") - for _, child := range children { - id := child.S("id").Data().(string) - name := child.S("name").Data().(string) - fmt.Printf("id: %10v name: %10v\n", id, name) - } - return errors.New("no on-line edge routers") - } - - fmt.Printf("Available edge routers: \n\n") - for idx, er := range ers { - fmt.Printf(" %v: %v\n", idx+1, er.name) - } - fmt.Print(" R: Refresh list from controller\n") - var val string - - if !ctx.Runner.AssumeDefault { - val, err = term.Prompt("\nSelect edge router, by number or name (default 1): ") - if err != nil { - return err - } - } - - if val == "" { - edgeRouterName = ers[0].name - valid = true - } else { - if idx, err := strconv.Atoi(val); err == nil { - if idx > 0 && idx <= len(ers) { - edgeRouterName = ers[idx-1].name - valid = true - } - } - } - - if !valid { - for _, er := range ers { - if val == er.name { - edgeRouterName = val - valid = true - } - } - } - - if !valid { - if strings.EqualFold("r", val) { - fmt.Println("Refreshing edge router list") - } else { - fmt.Printf("Invalid input %v\n", val) - } - } - } - - ctx.Runner.AddVariable("edgeRouterName", edgeRouterName) - return nil -} - -type PlainEchoServerActions struct { - server plainEchoServer -} - -func (self *PlainEchoServerActions) Start(ctx *tutorial.ActionContext) error { - if !ctx.Runner.AssumeDefault { - start, err := tutorial.AskYesNoWithDefault("Start plain-echo-server? [Y/N] (default Y): ", true) - if err != nil { - return err - } - if !start { - return nil - } - } - - if err := self.server.run(); err != nil { - return err - } - ctx.Runner.AddVariable("port", self.server.Port) - return nil -} - -func (self *PlainEchoServerActions) Stop(ctx *tutorial.ActionContext) error { - if !ctx.Runner.AssumeDefault { - start, err := tutorial.AskYesNoWithDefault("Stop plain-echo-server? [Y/N] (default Y): ", true) - if err != nil { - return err - } - if !start { - return nil - } - } - - if self.server.listener != nil { - return self.server.stop() - } - return nil -} - -type ZitiEchoServerActions struct { - server zitiEchoServer -} - -func (self *ZitiEchoServerActions) Start(ctx *tutorial.ActionContext) error { - logrus.SetLevel(logrus.WarnLevel) - - self.server.identityJson = "echo-server.json" - if !ctx.Runner.AssumeDefault { - start, err := tutorial.AskYesNoWithDefault("Start ziti-echo-server? [Y/N] (default Y): ", true) - if err != nil { - return err - } - if !start { - return nil - } - } - - if err := self.server.run(); err != nil { - return err - } - return nil -} - -func (self *ZitiEchoServerActions) Stop(*tutorial.ActionContext) error { - if self.server.listener != nil { - return self.server.stop() - } - return nil -} diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client.go b/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client.go deleted file mode 100644 index 73575f1e8..000000000 --- a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client.go +++ /dev/null @@ -1,27 +0,0 @@ -package edge - -import ( - "fmt" - "github.com/fatih/color" - "io" - "net/http" - "net/url" - "os" -) - -type plainEchoClient struct { - host string - port uint16 -} - -func (self *plainEchoClient) echo(input string) error { - input = url.QueryEscape(input) - u := fmt.Sprintf("http://%v:%v?input=%v", self.host, self.port, input) - resp, err := (&http.Client{}).Get(u) - if err == nil { - c := color.New(color.FgBlue, color.Bold) - c.Print("\nplain-http-echo-client: ") - _, err = io.Copy(os.Stdout, resp.Body) - } - return err -} diff --git a/ziti/cmd/ziti/cmd/tutorial/actions/keep_session_alive.go b/ziti/cmd/ziti/cmd/tutorial/actions/keep_session_alive.go new file mode 100644 index 000000000..53e64a17d --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/actions/keep_session_alive.go @@ -0,0 +1,49 @@ +/* + 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 actions + +import ( + "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/edge" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "net/url" + "time" +) + +type KeepSessionAliveAction struct{} + +func (self *KeepSessionAliveAction) Execute(ctx *tutorial.ActionContext) error { + interval := time.Minute + if val, ok := ctx.Headers["interval"]; ok { + if d, err := time.ParseDuration(val); err != nil { + return err + } else { + interval = d + } + } + fmt.Printf("Running session refresh every %v\n", interval) + go func() { + ticker := time.NewTicker(interval) + for { + select { + case <-ticker.C: + _, _, _ = edge.ListEntitiesOfType("edge-routers", url.Values{}, false, nil, 10, false) + } + } + }() + return nil +} diff --git a/ziti/cmd/ziti/cmd/tutorial/actions/select_edge_router.go b/ziti/cmd/ziti/cmd/tutorial/actions/select_edge_router.go new file mode 100644 index 000000000..35ea88345 --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/actions/select_edge_router.go @@ -0,0 +1,138 @@ +/* + 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 actions + +import ( + "fmt" + "github.com/openziti/foundation/util/term" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/edge" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "github.com/pkg/errors" + "strconv" + "strings" +) + +type edgeRouter struct { + id string + name string +} + +type SelectEdgeRouterAction struct{} + +func (self *SelectEdgeRouterAction) Execute(ctx *tutorial.ActionContext) error { + for { + err := self.SelectEdgeRouter(ctx) + if err == nil { + return nil + } + + retry, err2 := tutorial.AskYesNoWithDefault(fmt.Sprintf("Error getting edge router (err=%v). Try again? [Y/N] (default Y): ", err), true) + if err2 != nil { + fmt.Printf("encountered error prompting for input: %v\n", err2) + return err + } + + if !retry { + return err + } + } +} + +func (self *SelectEdgeRouterAction) SelectEdgeRouter(ctx *tutorial.ActionContext) error { + fmt.Println("") + + valid := false + var edgeRouterName string + + for !valid { + children, _, err := edge.ListEntitiesWithFilter("edge-routers", "limit none") + if err != nil { + return errors.Wrap(err, "unable to list edge routers") + } + + var ers []*edgeRouter + + if len(children) == 0 { + return errors.New("no edge routers found") + } + + for _, child := range children { + isOnline := child.S("isOnline").Data().(bool) + if isOnline { + id := child.S("id").Data().(string) + name := child.S("name").Data().(string) + ers = append(ers, &edgeRouter{id: id, name: name}) + } + } + + if len(ers) == 0 { + fmt.Println("Error: no online edge routers found. Found these offline edge routers: ") + for _, child := range children { + id := child.S("id").Data().(string) + name := child.S("name").Data().(string) + fmt.Printf("id: %10v name: %10v\n", id, name) + } + return errors.New("no on-line edge routers") + } + + fmt.Printf("Available edge routers: \n\n") + for idx, er := range ers { + fmt.Printf(" %v: %v\n", idx+1, er.name) + } + fmt.Print(" R: Refresh list from controller\n") + var val string + + if !ctx.Runner.AssumeDefault { + val, err = term.Prompt("\nSelect edge router, by number or name (default 1): ") + if err != nil { + return err + } + } + + if val == "" { + edgeRouterName = ers[0].name + valid = true + } else { + if idx, err := strconv.Atoi(val); err == nil { + if idx > 0 && idx <= len(ers) { + edgeRouterName = ers[idx-1].name + valid = true + } + } + } + + if !valid { + for _, er := range ers { + if val == er.name { + edgeRouterName = val + valid = true + } + } + } + + if !valid { + if strings.EqualFold("r", val) { + fmt.Println("Refreshing edge router list") + } else { + fmt.Printf("Invalid input %v\n", val) + } + } + } + + ctx.Runner.AddVariable("edgeRouterName", edgeRouterName) + return nil +} diff --git a/ziti/cmd/ziti/cmd/tutorial/actions/ziti_create_config.go b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_create_config.go new file mode 100644 index 000000000..c346bb58a --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_create_config.go @@ -0,0 +1,93 @@ +/* + 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 actions + +import ( + "fmt" + "github.com/fatih/color" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "github.com/pkg/errors" + "os" + "strings" +) + +type ZitiCreateConfigAction struct{} + +func (self *ZitiCreateConfigAction) Execute(ctx *tutorial.ActionContext) error { + if strings.EqualFold("true", ctx.Headers["templatize"]) { + body, err := ctx.Runner.Template(ctx.Body) + if err != nil { + return err + } + ctx.Body = body + } + name := ctx.Headers["name"] + configType := ctx.Headers["type"] + + buf := &strings.Builder{} + buf.WriteString("About to execute:\n\n") + + line := fmt.Sprintf("ziti edge create config %v %v '%v'", name, configType, ctx.Body) + params := tutorial.ParseArgumentsWithStrings(line) + if params[0] != "ziti" { + return errors.Errorf("invalid parameter for ziti action, must start with 'ziti': %v", ctx.Body) + } + params[0] = line + ctx.Runner.LeftPadBuilder(buf) + buf.WriteString(" ") + buf.WriteString(color.New(color.Bold).Sprintf(line)) + buf.WriteRune('\n') + buf.WriteRune('\n') + ctx.Runner.LeftPadBuilder(buf) + buf.WriteString("Continue [Y/N] (default Y): ") + + if !ctx.Runner.AssumeDefault { + tutorial.Continue(buf.String(), true) + } + + fmt.Println("") + c := color.New(color.FgBlue, color.Bold) + + colorStdOut := !strings.EqualFold("false", ctx.Headers["colorStdOut"]) + + allowRetry := strings.EqualFold("true", ctx.Headers["allowRetry"]) + failOk := strings.EqualFold("true", ctx.Headers["failOk"]) + _, _ = c.Printf("$ %v\n", line) + done := false + for !done { + if err := tutorial.Exec(os.Args[0], colorStdOut, "edge", "create", "config", name, configType, ctx.Body); err != nil { + if failOk { + return nil + } + if allowRetry { + retry, err2 := tutorial.AskYesNoWithDefault(fmt.Sprintf("operation failed with err: %v. Retry [Y/N] (default Y):", err), true) + if err2 != nil { + fmt.Printf("error while asking about retry: %v\n", err2) + return err + } + if !retry { + return err + } + } else { + return err + } + } else { + done = true + } + } + return nil +} diff --git a/ziti/cmd/ziti/cmd/tutorial/actions/ziti_ensure_logged_in.go b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_ensure_logged_in.go new file mode 100644 index 000000000..6798378c1 --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_ensure_logged_in.go @@ -0,0 +1,38 @@ +/* + 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 actions + +import ( + "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/edge" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "net/url" +) + +type ZitiEnsureLoggedIn struct { + LoginParams LoginParams +} + +func (self *ZitiEnsureLoggedIn) Execute(ctx *tutorial.ActionContext) error { + _, _, err := edge.ListEntitiesOfType("edge-routers", url.Values{}, false, nil, 10, false) + if err == nil { + fmt.Println("Already authenticated to Ziti Controller") + return nil + } + loginAction := &ZitiLoginAction{LoginParams: self.LoginParams} + return loginAction.Execute(ctx) +} diff --git a/ziti/cmd/ziti/cmd/tutorial/actions/ziti_login.go b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_login.go new file mode 100644 index 000000000..c4a4c00af --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_login.go @@ -0,0 +1,44 @@ +/* + 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 actions + +import "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + +type LoginParams interface { + GetControllerUrl() string + GetUsername() string + GetPassword() string +} + +type ZitiLoginAction struct { + LoginParams LoginParams +} + +func (self *ZitiLoginAction) Execute(ctx *tutorial.ActionContext) error { + cmd := "ziti edge login --ignore-config" + if self.LoginParams.GetControllerUrl() != "" { + cmd += " " + self.LoginParams.GetControllerUrl() + } + if self.LoginParams.GetUsername() != "" { + cmd += " --username " + self.LoginParams.GetUsername() + } + if self.LoginParams.GetPassword() != "" { + cmd += " --password " + self.LoginParams.GetPassword() + } + ctx.Body = cmd + return (&ZitiRunnerAction{}).Execute(ctx) +} diff --git a/ziti/cmd/ziti/cmd/tutorial/actions/ziti_runner.go b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_runner.go new file mode 100644 index 000000000..51826beb7 --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/actions/ziti_runner.go @@ -0,0 +1,99 @@ +/* + 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 actions + +import ( + "fmt" + "github.com/fatih/color" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "github.com/pkg/errors" + "os" + "strings" +) + +type ZitiRunnerAction struct{} + +func (self *ZitiRunnerAction) Execute(ctx *tutorial.ActionContext) error { + if strings.EqualFold("true", ctx.Headers["templatize"]) { + body, err := ctx.Runner.Template(ctx.Body) + if err != nil { + return err + } + ctx.Body = body + } + lines := strings.Split(ctx.Body, "\n") + var cmds [][]string + buf := &strings.Builder{} + buf.WriteString("About to execute:\n\n") + + for _, line := range lines { + line = strings.TrimSpace(line) + if len(line) > 0 { + params := tutorial.ParseArgumentsWithStrings(line) + if params[0] != "ziti" { + return errors.Errorf("invalid parameter for ziti action, must start with 'ziti': %v", ctx.Body) + } + params[0] = line + cmds = append(cmds, params) + ctx.Runner.LeftPadBuilder(buf) + buf.WriteString(" ") + buf.WriteString(color.New(color.Bold).Sprintf(line)) + buf.WriteRune('\n') + } + } + buf.WriteRune('\n') + ctx.Runner.LeftPadBuilder(buf) + buf.WriteString("Continue [Y/N] (default Y): ") + + if !ctx.Runner.AssumeDefault { + tutorial.Continue(buf.String(), true) + } + + fmt.Println("") + c := color.New(color.FgBlue, color.Bold) + + colorStdOut := !strings.EqualFold("false", ctx.Headers["colorStdOut"]) + + allowRetry := strings.EqualFold("true", ctx.Headers["allowRetry"]) + failOk := strings.EqualFold("true", ctx.Headers["failOk"]) + for _, cmd := range cmds { + _, _ = c.Printf("$ %v\n", cmd[0]) + done := false + for !done { + if err := tutorial.Exec(os.Args[0], colorStdOut, cmd[1:]...); err != nil { + if failOk { + return nil + } + if allowRetry { + retry, err2 := tutorial.AskYesNoWithDefault(fmt.Sprintf("operation failed with err: %v. Retry [Y/N] (default Y):", err), true) + if err2 != nil { + fmt.Printf("error while asking about retry: %v\n", err2) + return err + } + if !retry { + return err + } + } else { + return err + } + } else { + done = true + } + } + } + return nil +} diff --git a/ziti/cmd/ziti/cmd/tutorial/first-service-tutorial.go b/ziti/cmd/ziti/cmd/tutorial/first-service-tutorial.go new file mode 100644 index 000000000..e3c8f3e7f --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/first-service-tutorial.go @@ -0,0 +1,181 @@ +/* + 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 tutorial + +import ( + _ "embed" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/tutorial/actions" + "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "time" +) + +//go:embed tutorials/first-service.md +var firstServiceTutorialSource []byte + +//go:embed plain_echo_server.go +var plainEchoServerSource string + +//go:embed plain_echo_client.go +var plainEchoClientSource string + +//go:embed ziti_echo_client.go +var zitiEchoClientSource string + +//go:embed ziti_echo_server.go +var zitiEchoServerSource string + +type firstServiceTutorialOptions struct { + api.Options + TutorialOptions +} + +func newFirstServiceTutorialCmd(p common.OptionsProvider) *cobra.Command { + options := &firstServiceTutorialOptions{ + Options: api.Options{ + CommonOptions: p(), + }, + } + + cmd := &cobra.Command{ + Use: "first-service", + Short: "Walks you through creating a service, identity and policies", + Args: cobra.ExactArgs(0), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := options.run() + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVar(&options.ControllerUrl, "controller-url", "", "The Ziti controller URL to use") + cmd.Flags().StringVarP(&options.Username, "username", "u", "", "The Ziti controller username to use") + cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The Ziti controller password to use") + cmd.Flags().DurationVar(&options.NewlinePause, "newline-pause", time.Millisecond*10, "How long to pause between lines when scrolling") + cmd.Flags().BoolVar(&options.AssumeDefault, "assume-default", false, "Non-interactive mode, assuming default input when user input is required") + options.AddCommonFlags(cmd) + + return cmd +} + +func (self *firstServiceTutorialOptions) run() error { + t := tutorial.NewRunner() + t.NewLinePause = self.NewlinePause + t.AssumeDefault = self.AssumeDefault + + t.RegisterActionHandler("ziti", &actions.ZitiRunnerAction{}) + t.RegisterActionHandler("ziti-login", &actions.ZitiLoginAction{ + LoginParams: &self.TutorialOptions, + }) + t.RegisterActionHandler("keep-session-alive", &actions.KeepSessionAliveAction{}) + t.RegisterActionHandler("select-edge-router", &actions.SelectEdgeRouterAction{}) + + plainEchoServerActions := &PlainEchoServerActions{} + t.RegisterActionHandlerF("run-plain-echo-server", plainEchoServerActions.Start) + t.RegisterActionHandlerF("stop-plain-echo-server", plainEchoServerActions.Stop) + + zitiEchoServerActions := &ZitiEchoServerActions{} + t.RegisterActionHandlerF("run-ziti-echo-server", zitiEchoServerActions.Start) + t.RegisterActionHandlerF("stop-ziti-echo-server", zitiEchoServerActions.Stop) + + showActionHandler := tutorial.NewShowActionHandler() + showActionHandler.Add("echo_server_plain.go", plainEchoServerSource) + showActionHandler.Add("plain_echo_client.go", plainEchoClientSource) + showActionHandler.Add("echo_client_ziti.go", zitiEchoClientSource) + showActionHandler.Add("echo_server_ziti.go", zitiEchoServerSource) + t.RegisterActionHandler("show", showActionHandler) + + return t.Run(firstServiceTutorialSource) +} + +type PlainEchoServerActions struct { + server plainEchoServer +} + +func (self *PlainEchoServerActions) Start(ctx *tutorial.ActionContext) error { + if !ctx.Runner.AssumeDefault { + start, err := tutorial.AskYesNoWithDefault("Start plain-echo-server? [Y/N] (default Y): ", true) + if err != nil { + return err + } + if !start { + return nil + } + } + + if err := self.server.run(); err != nil { + return err + } + ctx.Runner.AddVariable("port", self.server.Port) + return nil +} + +func (self *PlainEchoServerActions) Stop(ctx *tutorial.ActionContext) error { + if !ctx.Runner.AssumeDefault { + start, err := tutorial.AskYesNoWithDefault("Stop plain-echo-server? [Y/N] (default Y): ", true) + if err != nil { + return err + } + if !start { + return nil + } + } + + if self.server.listener != nil { + return self.server.stop() + } + return nil +} + +type ZitiEchoServerActions struct { + server zitiEchoServer +} + +func (self *ZitiEchoServerActions) Start(ctx *tutorial.ActionContext) error { + logrus.SetLevel(logrus.WarnLevel) + + self.server.identityJson = "echo-server.json" + if !ctx.Runner.AssumeDefault { + start, err := tutorial.AskYesNoWithDefault("Start ziti-echo-server? [Y/N] (default Y): ", true) + if err != nil { + return err + } + if !start { + return nil + } + } + + if err := self.server.run(); err != nil { + return err + } + return nil +} + +func (self *ZitiEchoServerActions) Stop(*tutorial.ActionContext) error { + if self.server.listener != nil { + return self.server.stop() + } + return nil +} diff --git a/ziti/cmd/ziti/cmd/tutorial/plain_echo_client.go b/ziti/cmd/ziti/cmd/tutorial/plain_echo_client.go new file mode 100644 index 000000000..cfe78218c --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/plain_echo_client.go @@ -0,0 +1,43 @@ +/* + 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 tutorial + +import ( + "fmt" + "github.com/fatih/color" + "io" + "net/http" + "net/url" + "os" +) + +type plainEchoClient struct { + host string + port uint16 +} + +func (self *plainEchoClient) echo(input string) error { + input = url.QueryEscape(input) + u := fmt.Sprintf("http://%v:%v?input=%v", self.host, self.port, input) + resp, err := (&http.Client{}).Get(u) + if err == nil { + c := color.New(color.FgBlue, color.Bold) + c.Print("\nplain-http-echo-client: ") + _, err = io.Copy(os.Stdout, resp.Body) + } + return err +} diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client_cmd.go b/ziti/cmd/ziti/cmd/tutorial/plain_echo_client_cmd.go similarity index 67% rename from ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client_cmd.go rename to ziti/cmd/ziti/cmd/tutorial/plain_echo_client_cmd.go index bc8a06006..42b86e2f0 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client_cmd.go +++ b/ziti/cmd/ziti/cmd/tutorial/plain_echo_client_cmd.go @@ -1,4 +1,20 @@ -package edge +/* + 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 tutorial import ( "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server.go b/ziti/cmd/ziti/cmd/tutorial/plain_echo_server.go similarity index 63% rename from ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server.go rename to ziti/cmd/ziti/cmd/tutorial/plain_echo_server.go index cabba5590..cce649b93 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server.go +++ b/ziti/cmd/ziti/cmd/tutorial/plain_echo_server.go @@ -1,4 +1,20 @@ -package edge +/* + 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 tutorial import ( "fmt" diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server_cmd.go b/ziti/cmd/ziti/cmd/tutorial/plain_echo_server_cmd.go similarity index 66% rename from ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server_cmd.go rename to ziti/cmd/ziti/cmd/tutorial/plain_echo_server_cmd.go index c598c59c9..acc3e383a 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server_cmd.go +++ b/ziti/cmd/ziti/cmd/tutorial/plain_echo_server_cmd.go @@ -1,4 +1,20 @@ -package edge +/* + 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 tutorial import ( "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" diff --git a/ziti/cmd/ziti/cmd/tutorial/root.go b/ziti/cmd/ziti/cmd/tutorial/root.go new file mode 100644 index 000000000..0ea27d2a0 --- /dev/null +++ b/ziti/cmd/ziti/cmd/tutorial/root.go @@ -0,0 +1,68 @@ +/* + 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 tutorial + +import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/edge" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/spf13/cobra" + "time" +) + +func init() { + edge.ExtraEdgeCommands = append(edge.ExtraEdgeCommands, NewTutorialCmd) +} + +func NewTutorialCmd(p common.OptionsProvider) *cobra.Command { + cmd := &cobra.Command{ + Use: "tutorial", + Short: "Interactive tutorials for learning about Ziti", + Run: func(cmd *cobra.Command, args []string) { + err := cmd.Help() + cmdhelper.CheckErr(err) + }, + } + + cmd.AddCommand(newFirstServiceTutorialCmd(p)) + cmd.AddCommand(newPlainEchoServerCmd(p)) + cmd.AddCommand(newPlainEchoClientCmd(p)) + cmd.AddCommand(newZitiEchoClientCmd(p)) + cmd.AddCommand(newZitiEchoServerCmd(p)) + + return cmd +} + +type TutorialOptions struct { + ControllerUrl string + Username string + Password string + NewlinePause time.Duration + AssumeDefault bool +} + +func (self *TutorialOptions) GetControllerUrl() string { + return self.ControllerUrl +} + +func (self *TutorialOptions) GetUsername() string { + return self.Username +} + +func (self *TutorialOptions) GetPassword() string { + return self.Password +} diff --git a/ziti/cmd/ziti/cmd/edge/tutorials/first-service.md b/ziti/cmd/ziti/cmd/tutorial/tutorials/first-service.md similarity index 100% rename from ziti/cmd/ziti/cmd/edge/tutorials/first-service.md rename to ziti/cmd/ziti/cmd/tutorial/tutorials/first-service.md diff --git a/ziti/cmd/ziti/cmd/edge/tutorials/more-info.md b/ziti/cmd/ziti/cmd/tutorial/tutorials/more-info.md similarity index 100% rename from ziti/cmd/ziti/cmd/edge/tutorials/more-info.md rename to ziti/cmd/ziti/cmd/tutorial/tutorials/more-info.md diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client.go b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_client.go similarity index 66% rename from ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client.go rename to ziti/cmd/ziti/cmd/tutorial/ziti_echo_client.go index 7e3a392aa..0dd326afb 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client.go +++ b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_client.go @@ -1,4 +1,20 @@ -package edge +/* + 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 tutorial import ( "context" diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client_cmd.go b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_client_cmd.go similarity index 67% rename from ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client_cmd.go rename to ziti/cmd/ziti/cmd/tutorial/ziti_echo_client_cmd.go index 0d9b51aef..4643271a2 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client_cmd.go +++ b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_client_cmd.go @@ -1,4 +1,20 @@ -package edge +/* + 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 tutorial import ( "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server.go b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_server.go similarity index 66% rename from ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server.go rename to ziti/cmd/ziti/cmd/tutorial/ziti_echo_server.go index 235471ef1..331fcf5c2 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server.go +++ b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_server.go @@ -1,4 +1,20 @@ -package edge +/* + 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 tutorial import ( "fmt" diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server_cmd.go b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_server_cmd.go similarity index 66% rename from ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server_cmd.go rename to ziti/cmd/ziti/cmd/tutorial/ziti_echo_server_cmd.go index d2b5908b8..165f433e4 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server_cmd.go +++ b/ziti/cmd/ziti/cmd/tutorial/ziti_echo_server_cmd.go @@ -1,4 +1,20 @@ -package edge +/* + 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 tutorial import ( "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common"