Refactor tutorial code. Add initial demo commands

This commit is contained in:
Paul Lorenz
2022-04-07 21:02:19 -04:00
parent 75f0828b24
commit 7d93b8cbff
39 changed files with 1891 additions and 626 deletions
+13 -1
View File
@@ -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
+6 -4
View File
@@ -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 {
+10 -6
View File
@@ -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)
@@ -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
+209 -109
View File
@@ -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
}
+16 -13
View File
@@ -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;
}
+41 -10
View File
@@ -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)
+14 -8
View File
@@ -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,
+11
View File
@@ -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)
+166
View File
@@ -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)
}
}
+41
View File
@@ -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
}
@@ -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
```
@@ -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
```
@@ -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)
}
@@ -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)
}
+128
View File
@@ -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 <destination>",
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")
}
}
+1 -1
View File
@@ -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
}
+11 -11
View File
@@ -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
}
+9 -3
View File
@@ -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
}
-426
View File
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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)
}
@@ -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)
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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"
@@ -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"
@@ -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"
+68
View File
@@ -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
}
@@ -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"
@@ -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"
@@ -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"
@@ -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"