diff --git a/README.md b/README.md index d92f57de..fedf89b4 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,8 @@ spec: mountPath: \\.\pipe\csi-proxy-volume-v1alpha1 - name: csi-proxy-filesystem-pipe mountPath: \\.\pipe\csi-proxy-filesystem-v1alpha1 + - name: csi-proxy-iscsi-pipe + mountPath: \\.\pipe\csi-proxy-iscsi-v1alpha1 volumes: - name: csi-proxy-disk-pipe hostPath: @@ -112,6 +114,10 @@ spec: hostPath: path: \\.\pipe\csi-proxy-filesystem-v1alpha1 type: "" + - name: csi-proxy-iscsi-pipe + hostPath: + path: \\.\pipe\csi-proxy-iscsi-v1alpha1 + type: "" - name: registration-dir hostPath: path: C:\var\lib\kubelet\plugins_registry\ diff --git a/client/api/iscsi/v1alpha1/api.pb.go b/client/api/iscsi/v1alpha1/api.pb.go new file mode 100644 index 00000000..9ba7f6a4 --- /dev/null +++ b/client/api/iscsi/v1alpha1/api.pb.go @@ -0,0 +1,1077 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto + +package v1alpha1 + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// 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 + +type AuthenticationType int32 + +const ( + // No authentication is used + AuthenticationType_NONE AuthenticationType = 0 + // One way CHAP authentication. The target authenticates the initiator. + AuthenticationType_ONE_WAY_CHAP AuthenticationType = 1 + // Mutual CHAP authentication. The target and initiator authenticate each + // other. + AuthenticationType_MUTUAL_CHAP AuthenticationType = 2 +) + +var AuthenticationType_name = map[int32]string{ + 0: "NONE", + 1: "ONE_WAY_CHAP", + 2: "MUTUAL_CHAP", +} + +var AuthenticationType_value = map[string]int32{ + "NONE": 0, + "ONE_WAY_CHAP": 1, + "MUTUAL_CHAP": 2, +} + +func (x AuthenticationType) String() string { + return proto.EnumName(AuthenticationType_name, int32(x)) +} + +func (AuthenticationType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{0} +} + +// TargetPortal is an address and port pair for a specific iSCSI storage +// target. +type TargetPortal struct { + // iSCSI Target (server) address + TargetAddress string `protobuf:"bytes,1,opt,name=target_address,json=targetAddress,proto3" json:"target_address,omitempty"` + // iSCSI Target port (default iSCSI port is 3260) + TargetPort uint32 `protobuf:"varint,2,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TargetPortal) Reset() { *m = TargetPortal{} } +func (m *TargetPortal) String() string { return proto.CompactTextString(m) } +func (*TargetPortal) ProtoMessage() {} +func (*TargetPortal) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{0} +} + +func (m *TargetPortal) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TargetPortal.Unmarshal(m, b) +} +func (m *TargetPortal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TargetPortal.Marshal(b, m, deterministic) +} +func (m *TargetPortal) XXX_Merge(src proto.Message) { + xxx_messageInfo_TargetPortal.Merge(m, src) +} +func (m *TargetPortal) XXX_Size() int { + return xxx_messageInfo_TargetPortal.Size(m) +} +func (m *TargetPortal) XXX_DiscardUnknown() { + xxx_messageInfo_TargetPortal.DiscardUnknown(m) +} + +var xxx_messageInfo_TargetPortal proto.InternalMessageInfo + +func (m *TargetPortal) GetTargetAddress() string { + if m != nil { + return m.TargetAddress + } + return "" +} + +func (m *TargetPortal) GetTargetPort() uint32 { + if m != nil { + return m.TargetPort + } + return 0 +} + +type AddTargetPortalRequest struct { + // iSCSI Target Portal to register in the initiator + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddTargetPortalRequest) Reset() { *m = AddTargetPortalRequest{} } +func (m *AddTargetPortalRequest) String() string { return proto.CompactTextString(m) } +func (*AddTargetPortalRequest) ProtoMessage() {} +func (*AddTargetPortalRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{1} +} + +func (m *AddTargetPortalRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddTargetPortalRequest.Unmarshal(m, b) +} +func (m *AddTargetPortalRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddTargetPortalRequest.Marshal(b, m, deterministic) +} +func (m *AddTargetPortalRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddTargetPortalRequest.Merge(m, src) +} +func (m *AddTargetPortalRequest) XXX_Size() int { + return xxx_messageInfo_AddTargetPortalRequest.Size(m) +} +func (m *AddTargetPortalRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AddTargetPortalRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AddTargetPortalRequest proto.InternalMessageInfo + +func (m *AddTargetPortalRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +type AddTargetPortalResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddTargetPortalResponse) Reset() { *m = AddTargetPortalResponse{} } +func (m *AddTargetPortalResponse) String() string { return proto.CompactTextString(m) } +func (*AddTargetPortalResponse) ProtoMessage() {} +func (*AddTargetPortalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{2} +} + +func (m *AddTargetPortalResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddTargetPortalResponse.Unmarshal(m, b) +} +func (m *AddTargetPortalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddTargetPortalResponse.Marshal(b, m, deterministic) +} +func (m *AddTargetPortalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddTargetPortalResponse.Merge(m, src) +} +func (m *AddTargetPortalResponse) XXX_Size() int { + return xxx_messageInfo_AddTargetPortalResponse.Size(m) +} +func (m *AddTargetPortalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AddTargetPortalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AddTargetPortalResponse proto.InternalMessageInfo + +type DiscoverTargetPortalRequest struct { + // iSCSI Target Portal on which to initiate discovery + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DiscoverTargetPortalRequest) Reset() { *m = DiscoverTargetPortalRequest{} } +func (m *DiscoverTargetPortalRequest) String() string { return proto.CompactTextString(m) } +func (*DiscoverTargetPortalRequest) ProtoMessage() {} +func (*DiscoverTargetPortalRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{3} +} + +func (m *DiscoverTargetPortalRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DiscoverTargetPortalRequest.Unmarshal(m, b) +} +func (m *DiscoverTargetPortalRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DiscoverTargetPortalRequest.Marshal(b, m, deterministic) +} +func (m *DiscoverTargetPortalRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DiscoverTargetPortalRequest.Merge(m, src) +} +func (m *DiscoverTargetPortalRequest) XXX_Size() int { + return xxx_messageInfo_DiscoverTargetPortalRequest.Size(m) +} +func (m *DiscoverTargetPortalRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DiscoverTargetPortalRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DiscoverTargetPortalRequest proto.InternalMessageInfo + +func (m *DiscoverTargetPortalRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +type DiscoverTargetPortalResponse struct { + // List of discovered IQN addresses + // follows IQN format: iqn.yyyy-mm.naming-authority:unique-name + Iqns []string `protobuf:"bytes,1,rep,name=iqns,proto3" json:"iqns,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DiscoverTargetPortalResponse) Reset() { *m = DiscoverTargetPortalResponse{} } +func (m *DiscoverTargetPortalResponse) String() string { return proto.CompactTextString(m) } +func (*DiscoverTargetPortalResponse) ProtoMessage() {} +func (*DiscoverTargetPortalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{4} +} + +func (m *DiscoverTargetPortalResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DiscoverTargetPortalResponse.Unmarshal(m, b) +} +func (m *DiscoverTargetPortalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DiscoverTargetPortalResponse.Marshal(b, m, deterministic) +} +func (m *DiscoverTargetPortalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DiscoverTargetPortalResponse.Merge(m, src) +} +func (m *DiscoverTargetPortalResponse) XXX_Size() int { + return xxx_messageInfo_DiscoverTargetPortalResponse.Size(m) +} +func (m *DiscoverTargetPortalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DiscoverTargetPortalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DiscoverTargetPortalResponse proto.InternalMessageInfo + +func (m *DiscoverTargetPortalResponse) GetIqns() []string { + if m != nil { + return m.Iqns + } + return nil +} + +type RemoveTargetPortalRequest struct { + // iSCSI Target Portal + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveTargetPortalRequest) Reset() { *m = RemoveTargetPortalRequest{} } +func (m *RemoveTargetPortalRequest) String() string { return proto.CompactTextString(m) } +func (*RemoveTargetPortalRequest) ProtoMessage() {} +func (*RemoveTargetPortalRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{5} +} + +func (m *RemoveTargetPortalRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveTargetPortalRequest.Unmarshal(m, b) +} +func (m *RemoveTargetPortalRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveTargetPortalRequest.Marshal(b, m, deterministic) +} +func (m *RemoveTargetPortalRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveTargetPortalRequest.Merge(m, src) +} +func (m *RemoveTargetPortalRequest) XXX_Size() int { + return xxx_messageInfo_RemoveTargetPortalRequest.Size(m) +} +func (m *RemoveTargetPortalRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveTargetPortalRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveTargetPortalRequest proto.InternalMessageInfo + +func (m *RemoveTargetPortalRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +type RemoveTargetPortalResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveTargetPortalResponse) Reset() { *m = RemoveTargetPortalResponse{} } +func (m *RemoveTargetPortalResponse) String() string { return proto.CompactTextString(m) } +func (*RemoveTargetPortalResponse) ProtoMessage() {} +func (*RemoveTargetPortalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{6} +} + +func (m *RemoveTargetPortalResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveTargetPortalResponse.Unmarshal(m, b) +} +func (m *RemoveTargetPortalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveTargetPortalResponse.Marshal(b, m, deterministic) +} +func (m *RemoveTargetPortalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveTargetPortalResponse.Merge(m, src) +} +func (m *RemoveTargetPortalResponse) XXX_Size() int { + return xxx_messageInfo_RemoveTargetPortalResponse.Size(m) +} +func (m *RemoveTargetPortalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveTargetPortalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveTargetPortalResponse proto.InternalMessageInfo + +type ListTargetPortalsRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTargetPortalsRequest) Reset() { *m = ListTargetPortalsRequest{} } +func (m *ListTargetPortalsRequest) String() string { return proto.CompactTextString(m) } +func (*ListTargetPortalsRequest) ProtoMessage() {} +func (*ListTargetPortalsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{7} +} + +func (m *ListTargetPortalsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListTargetPortalsRequest.Unmarshal(m, b) +} +func (m *ListTargetPortalsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListTargetPortalsRequest.Marshal(b, m, deterministic) +} +func (m *ListTargetPortalsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTargetPortalsRequest.Merge(m, src) +} +func (m *ListTargetPortalsRequest) XXX_Size() int { + return xxx_messageInfo_ListTargetPortalsRequest.Size(m) +} +func (m *ListTargetPortalsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListTargetPortalsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListTargetPortalsRequest proto.InternalMessageInfo + +type ListTargetPortalsResponse struct { + // A list of Target Portals currently registered in the initiator + TargetPortals []*TargetPortal `protobuf:"bytes,1,rep,name=target_portals,json=targetPortals,proto3" json:"target_portals,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTargetPortalsResponse) Reset() { *m = ListTargetPortalsResponse{} } +func (m *ListTargetPortalsResponse) String() string { return proto.CompactTextString(m) } +func (*ListTargetPortalsResponse) ProtoMessage() {} +func (*ListTargetPortalsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{8} +} + +func (m *ListTargetPortalsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListTargetPortalsResponse.Unmarshal(m, b) +} +func (m *ListTargetPortalsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListTargetPortalsResponse.Marshal(b, m, deterministic) +} +func (m *ListTargetPortalsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTargetPortalsResponse.Merge(m, src) +} +func (m *ListTargetPortalsResponse) XXX_Size() int { + return xxx_messageInfo_ListTargetPortalsResponse.Size(m) +} +func (m *ListTargetPortalsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListTargetPortalsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListTargetPortalsResponse proto.InternalMessageInfo + +func (m *ListTargetPortalsResponse) GetTargetPortals() []*TargetPortal { + if m != nil { + return m.TargetPortals + } + return nil +} + +type ConnectTargetRequest struct { + // Target portal to which the initiator will connect + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + // IQN of the iSCSI Target + Iqn string `protobuf:"bytes,2,opt,name=iqn,proto3" json:"iqn,omitempty"` + // Connection authentication type, None by default + // + // One Way Chap uses the chap_username and chap_secret + // fields mentioned below to authenticate the initiator. + // + // Mutual Chap uses both the user/secret mentioned below + // and the Initiator Chap Secret to authenticate the target and initiator. + AuthType AuthenticationType `protobuf:"varint,3,opt,name=auth_type,json=authType,proto3,enum=v1alpha1.AuthenticationType" json:"auth_type,omitempty"` + // CHAP Username used to authenticate the initiator + ChapUsername string `protobuf:"bytes,4,opt,name=chap_username,json=chapUsername,proto3" json:"chap_username,omitempty"` + // CHAP password used to authenticate the initiator + ChapSecret string `protobuf:"bytes,5,opt,name=chap_secret,json=chapSecret,proto3" json:"chap_secret,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConnectTargetRequest) Reset() { *m = ConnectTargetRequest{} } +func (m *ConnectTargetRequest) String() string { return proto.CompactTextString(m) } +func (*ConnectTargetRequest) ProtoMessage() {} +func (*ConnectTargetRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{9} +} + +func (m *ConnectTargetRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConnectTargetRequest.Unmarshal(m, b) +} +func (m *ConnectTargetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConnectTargetRequest.Marshal(b, m, deterministic) +} +func (m *ConnectTargetRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConnectTargetRequest.Merge(m, src) +} +func (m *ConnectTargetRequest) XXX_Size() int { + return xxx_messageInfo_ConnectTargetRequest.Size(m) +} +func (m *ConnectTargetRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ConnectTargetRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ConnectTargetRequest proto.InternalMessageInfo + +func (m *ConnectTargetRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +func (m *ConnectTargetRequest) GetIqn() string { + if m != nil { + return m.Iqn + } + return "" +} + +func (m *ConnectTargetRequest) GetAuthType() AuthenticationType { + if m != nil { + return m.AuthType + } + return AuthenticationType_NONE +} + +func (m *ConnectTargetRequest) GetChapUsername() string { + if m != nil { + return m.ChapUsername + } + return "" +} + +func (m *ConnectTargetRequest) GetChapSecret() string { + if m != nil { + return m.ChapSecret + } + return "" +} + +type ConnectTargetResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConnectTargetResponse) Reset() { *m = ConnectTargetResponse{} } +func (m *ConnectTargetResponse) String() string { return proto.CompactTextString(m) } +func (*ConnectTargetResponse) ProtoMessage() {} +func (*ConnectTargetResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{10} +} + +func (m *ConnectTargetResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConnectTargetResponse.Unmarshal(m, b) +} +func (m *ConnectTargetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConnectTargetResponse.Marshal(b, m, deterministic) +} +func (m *ConnectTargetResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConnectTargetResponse.Merge(m, src) +} +func (m *ConnectTargetResponse) XXX_Size() int { + return xxx_messageInfo_ConnectTargetResponse.Size(m) +} +func (m *ConnectTargetResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ConnectTargetResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ConnectTargetResponse proto.InternalMessageInfo + +type GetTargetDisksRequest struct { + // Target portal whose disks will be queried + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + // IQN of the iSCSI Target + Iqn string `protobuf:"bytes,2,opt,name=iqn,proto3" json:"iqn,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTargetDisksRequest) Reset() { *m = GetTargetDisksRequest{} } +func (m *GetTargetDisksRequest) String() string { return proto.CompactTextString(m) } +func (*GetTargetDisksRequest) ProtoMessage() {} +func (*GetTargetDisksRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{11} +} + +func (m *GetTargetDisksRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTargetDisksRequest.Unmarshal(m, b) +} +func (m *GetTargetDisksRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTargetDisksRequest.Marshal(b, m, deterministic) +} +func (m *GetTargetDisksRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTargetDisksRequest.Merge(m, src) +} +func (m *GetTargetDisksRequest) XXX_Size() int { + return xxx_messageInfo_GetTargetDisksRequest.Size(m) +} +func (m *GetTargetDisksRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetTargetDisksRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTargetDisksRequest proto.InternalMessageInfo + +func (m *GetTargetDisksRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +func (m *GetTargetDisksRequest) GetIqn() string { + if m != nil { + return m.Iqn + } + return "" +} + +type GetTargetDisksResponse struct { + // List composed of disk ids (numbers) that are associated with the + // iSCSI target + DiskIDs []string `protobuf:"bytes,1,rep,name=diskIDs,proto3" json:"diskIDs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTargetDisksResponse) Reset() { *m = GetTargetDisksResponse{} } +func (m *GetTargetDisksResponse) String() string { return proto.CompactTextString(m) } +func (*GetTargetDisksResponse) ProtoMessage() {} +func (*GetTargetDisksResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{12} +} + +func (m *GetTargetDisksResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTargetDisksResponse.Unmarshal(m, b) +} +func (m *GetTargetDisksResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTargetDisksResponse.Marshal(b, m, deterministic) +} +func (m *GetTargetDisksResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTargetDisksResponse.Merge(m, src) +} +func (m *GetTargetDisksResponse) XXX_Size() int { + return xxx_messageInfo_GetTargetDisksResponse.Size(m) +} +func (m *GetTargetDisksResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetTargetDisksResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTargetDisksResponse proto.InternalMessageInfo + +func (m *GetTargetDisksResponse) GetDiskIDs() []string { + if m != nil { + return m.DiskIDs + } + return nil +} + +type DisconnectTargetRequest struct { + // Target portal from which initiator will disconnect + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + // IQN of the iSCSI Target + Iqn string `protobuf:"bytes,2,opt,name=iqn,proto3" json:"iqn,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DisconnectTargetRequest) Reset() { *m = DisconnectTargetRequest{} } +func (m *DisconnectTargetRequest) String() string { return proto.CompactTextString(m) } +func (*DisconnectTargetRequest) ProtoMessage() {} +func (*DisconnectTargetRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{13} +} + +func (m *DisconnectTargetRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DisconnectTargetRequest.Unmarshal(m, b) +} +func (m *DisconnectTargetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DisconnectTargetRequest.Marshal(b, m, deterministic) +} +func (m *DisconnectTargetRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DisconnectTargetRequest.Merge(m, src) +} +func (m *DisconnectTargetRequest) XXX_Size() int { + return xxx_messageInfo_DisconnectTargetRequest.Size(m) +} +func (m *DisconnectTargetRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DisconnectTargetRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DisconnectTargetRequest proto.InternalMessageInfo + +func (m *DisconnectTargetRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +func (m *DisconnectTargetRequest) GetIqn() string { + if m != nil { + return m.Iqn + } + return "" +} + +type DisconnectTargetResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DisconnectTargetResponse) Reset() { *m = DisconnectTargetResponse{} } +func (m *DisconnectTargetResponse) String() string { return proto.CompactTextString(m) } +func (*DisconnectTargetResponse) ProtoMessage() {} +func (*DisconnectTargetResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{14} +} + +func (m *DisconnectTargetResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DisconnectTargetResponse.Unmarshal(m, b) +} +func (m *DisconnectTargetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DisconnectTargetResponse.Marshal(b, m, deterministic) +} +func (m *DisconnectTargetResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DisconnectTargetResponse.Merge(m, src) +} +func (m *DisconnectTargetResponse) XXX_Size() int { + return xxx_messageInfo_DisconnectTargetResponse.Size(m) +} +func (m *DisconnectTargetResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DisconnectTargetResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DisconnectTargetResponse proto.InternalMessageInfo + +func init() { + proto.RegisterEnum("v1alpha1.AuthenticationType", AuthenticationType_name, AuthenticationType_value) + proto.RegisterType((*TargetPortal)(nil), "v1alpha1.TargetPortal") + proto.RegisterType((*AddTargetPortalRequest)(nil), "v1alpha1.AddTargetPortalRequest") + proto.RegisterType((*AddTargetPortalResponse)(nil), "v1alpha1.AddTargetPortalResponse") + proto.RegisterType((*DiscoverTargetPortalRequest)(nil), "v1alpha1.DiscoverTargetPortalRequest") + proto.RegisterType((*DiscoverTargetPortalResponse)(nil), "v1alpha1.DiscoverTargetPortalResponse") + proto.RegisterType((*RemoveTargetPortalRequest)(nil), "v1alpha1.RemoveTargetPortalRequest") + proto.RegisterType((*RemoveTargetPortalResponse)(nil), "v1alpha1.RemoveTargetPortalResponse") + proto.RegisterType((*ListTargetPortalsRequest)(nil), "v1alpha1.ListTargetPortalsRequest") + proto.RegisterType((*ListTargetPortalsResponse)(nil), "v1alpha1.ListTargetPortalsResponse") + proto.RegisterType((*ConnectTargetRequest)(nil), "v1alpha1.ConnectTargetRequest") + proto.RegisterType((*ConnectTargetResponse)(nil), "v1alpha1.ConnectTargetResponse") + proto.RegisterType((*GetTargetDisksRequest)(nil), "v1alpha1.GetTargetDisksRequest") + proto.RegisterType((*GetTargetDisksResponse)(nil), "v1alpha1.GetTargetDisksResponse") + proto.RegisterType((*DisconnectTargetRequest)(nil), "v1alpha1.DisconnectTargetRequest") + proto.RegisterType((*DisconnectTargetResponse)(nil), "v1alpha1.DisconnectTargetResponse") +} + +func init() { + proto.RegisterFile("github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto", fileDescriptor_0438d9bfe30f1df4) +} + +var fileDescriptor_0438d9bfe30f1df4 = []byte{ + // 649 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x6d, 0x4f, 0xd3, 0x50, + 0x14, 0xa6, 0xbc, 0x28, 0x3b, 0xac, 0x30, 0x6f, 0x78, 0x29, 0x95, 0xc8, 0xb8, 0x88, 0x59, 0x4c, + 0xd8, 0xc2, 0xfc, 0x64, 0x0c, 0x31, 0x15, 0x08, 0x92, 0x20, 0x90, 0xca, 0x14, 0x67, 0xe2, 0x72, + 0xd7, 0x5d, 0xd7, 0x9b, 0x6d, 0x6d, 0xd7, 0x7b, 0xbb, 0xb8, 0x1f, 0xe2, 0x5f, 0xf4, 0x77, 0x98, + 0xbe, 0xac, 0xeb, 0xb6, 0x6e, 0x7e, 0x70, 0x7c, 0xeb, 0x7d, 0xee, 0x73, 0x9e, 0x73, 0xee, 0x79, + 0x2b, 0x5c, 0x36, 0x99, 0x30, 0xbd, 0x7a, 0xd1, 0xb0, 0x3b, 0xa5, 0x96, 0x57, 0xa7, 0xae, 0x45, + 0x05, 0xe5, 0xc7, 0x06, 0x67, 0x25, 0x83, 0xb3, 0x63, 0xc7, 0xb5, 0x7f, 0xf5, 0x4b, 0x46, 0x9b, + 0x51, 0x4b, 0x94, 0x88, 0xc3, 0x4a, 0x8c, 0xfb, 0x57, 0xbd, 0x13, 0xd2, 0x76, 0x4c, 0x72, 0xe2, + 0x43, 0x45, 0xc7, 0xb5, 0x85, 0x8d, 0x56, 0x07, 0x18, 0xfe, 0x02, 0xd9, 0x7b, 0xe2, 0x36, 0xa9, + 0xb8, 0xb3, 0x5d, 0x41, 0xda, 0xe8, 0x08, 0xd6, 0x45, 0x70, 0xae, 0x91, 0x46, 0xc3, 0xa5, 0x9c, + 0x2b, 0x52, 0x5e, 0x2a, 0x64, 0x74, 0x39, 0x44, 0xb5, 0x10, 0x44, 0xfb, 0xb0, 0x16, 0xd1, 0x1c, + 0xdb, 0x15, 0xca, 0x62, 0x5e, 0x2a, 0xc8, 0x3a, 0x88, 0x58, 0x09, 0x57, 0x60, 0x5b, 0x6b, 0x34, + 0x92, 0xd2, 0x3a, 0xed, 0x7a, 0x94, 0x0b, 0xf4, 0x0e, 0xe4, 0x84, 0x29, 0x69, 0x07, 0x0e, 0xd6, + 0xca, 0xdb, 0xc5, 0x41, 0x4c, 0xc5, 0x11, 0xab, 0xac, 0x48, 0x9c, 0xf0, 0x2e, 0xec, 0x4c, 0xc8, + 0x72, 0xc7, 0xb6, 0x38, 0xc5, 0x55, 0x78, 0x7e, 0xce, 0xb8, 0x61, 0xf7, 0xa8, 0x3b, 0x77, 0xb7, + 0x65, 0xd8, 0x4b, 0xd7, 0x0e, 0x7d, 0x23, 0x04, 0xcb, 0xac, 0x6b, 0xf9, 0xb9, 0x5a, 0x2a, 0x64, + 0xf4, 0xe0, 0x1b, 0x3f, 0xc0, 0xae, 0x4e, 0x3b, 0x76, 0x8f, 0xce, 0x3d, 0x9a, 0x3d, 0x50, 0xd3, + 0x94, 0xa3, 0x3c, 0xa8, 0xa0, 0x5c, 0x33, 0x2e, 0x92, 0x77, 0x3c, 0x72, 0x8b, 0xab, 0xb0, 0x9b, + 0x72, 0x17, 0x3d, 0xe2, 0x34, 0x2e, 0x7d, 0x18, 0x53, 0xf8, 0x9c, 0xe9, 0x41, 0xc9, 0xc9, 0xa0, + 0x38, 0xfe, 0x23, 0xc1, 0xe6, 0x99, 0x6d, 0x59, 0xd4, 0x88, 0xf4, 0xe7, 0xf1, 0x56, 0x94, 0x83, + 0x25, 0xd6, 0xb5, 0x82, 0x06, 0xcb, 0xe8, 0xfe, 0x27, 0x7a, 0x0b, 0x19, 0xe2, 0x09, 0xb3, 0x26, + 0xfa, 0x0e, 0x55, 0x96, 0xf2, 0x52, 0x61, 0xbd, 0xbc, 0x37, 0x94, 0xd2, 0x3c, 0x61, 0x52, 0x4b, + 0x30, 0x83, 0x08, 0x66, 0x5b, 0xf7, 0x7d, 0x87, 0xea, 0xab, 0x3e, 0xdd, 0xff, 0x42, 0x87, 0x20, + 0x1b, 0x26, 0x71, 0x6a, 0x1e, 0xa7, 0xae, 0x45, 0x3a, 0x54, 0x59, 0x0e, 0x64, 0xb3, 0x3e, 0x58, + 0x89, 0x30, 0xbf, 0xb5, 0x03, 0x12, 0xa7, 0x86, 0x4b, 0x85, 0xb2, 0x12, 0x50, 0xc0, 0x87, 0x3e, + 0x07, 0x08, 0xde, 0x81, 0xad, 0xb1, 0x77, 0x46, 0x99, 0xff, 0x09, 0x5b, 0x97, 0x34, 0x02, 0xcf, + 0x19, 0x6f, 0xf1, 0xc7, 0xc9, 0x00, 0x2e, 0xc3, 0xf6, 0xb8, 0x9f, 0xa8, 0x84, 0x0a, 0x3c, 0x6d, + 0x30, 0xde, 0xba, 0x3a, 0x1f, 0xb4, 0xe2, 0xe0, 0x88, 0x4d, 0xd8, 0x09, 0x3a, 0xf8, 0xd1, 0xeb, + 0xe3, 0xf7, 0xdf, 0xa4, 0xa7, 0x30, 0xbe, 0xd7, 0x1a, 0xa0, 0xc9, 0x02, 0xa1, 0x55, 0x58, 0xbe, + 0xb9, 0xbd, 0xb9, 0xc8, 0x2d, 0xa0, 0x1c, 0x64, 0x6f, 0x6f, 0x2e, 0x6a, 0x5f, 0xb5, 0x6f, 0xb5, + 0xb3, 0x8f, 0xda, 0x5d, 0x4e, 0x42, 0x1b, 0xb0, 0xf6, 0xa9, 0x72, 0x5f, 0xd1, 0xae, 0x43, 0x60, + 0xb1, 0xfc, 0x7b, 0x05, 0x56, 0xae, 0xfc, 0xbd, 0x86, 0x1e, 0x60, 0x63, 0x6c, 0x17, 0xa0, 0x7c, + 0xa2, 0x11, 0x52, 0xb7, 0x8f, 0x7a, 0x30, 0x83, 0x11, 0x95, 0x71, 0x01, 0x35, 0x61, 0x33, 0x6d, + 0xdc, 0xd1, 0xd1, 0xd0, 0x78, 0xc6, 0xaa, 0x51, 0x5f, 0xfd, 0x8b, 0x16, 0x3b, 0x22, 0x80, 0x26, + 0x27, 0x19, 0x1d, 0x0e, 0xed, 0xa7, 0x6e, 0x10, 0xf5, 0xe5, 0x6c, 0x52, 0xec, 0xe2, 0x07, 0x3c, + 0x9b, 0x18, 0x79, 0x84, 0x87, 0xc6, 0xd3, 0x76, 0x85, 0x7a, 0x38, 0x93, 0x13, 0xeb, 0xeb, 0x20, + 0x8f, 0x4c, 0x03, 0x7a, 0x31, 0xb4, 0x4b, 0x5b, 0x07, 0xea, 0xfe, 0xd4, 0xfb, 0x58, 0xf3, 0x3b, + 0xe4, 0xc6, 0x5b, 0x08, 0x1d, 0x8c, 0x25, 0x35, 0x45, 0x19, 0xcf, 0xa2, 0xc4, 0xe2, 0x15, 0x58, + 0x1f, 0x9d, 0x1e, 0x94, 0x88, 0x28, 0x75, 0x7e, 0xd5, 0xfc, 0x74, 0xc2, 0x40, 0xf6, 0xc3, 0xfb, + 0xea, 0xe9, 0x7f, 0xfd, 0x9d, 0xeb, 0x4f, 0x82, 0x5f, 0xf3, 0x9b, 0xbf, 0x01, 0x00, 0x00, 0xff, + 0xff, 0xbb, 0x3d, 0x8f, 0x5c, 0xe5, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// IscsiClient is the client API for Iscsi service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type IscsiClient interface { + // AddTargetPortal registers an iSCSI target network address for later + // discovery. + // AddTargetPortal currently does not support selecting different NICs or + // a different iSCSI initiator (e.g a hardware initiator). This means that + // Windows will select the initiator NIC and instance on its own. + AddTargetPortal(ctx context.Context, in *AddTargetPortalRequest, opts ...grpc.CallOption) (*AddTargetPortalResponse, error) + // DiscoverTargetPortal initiates discovery on an iSCSI target network address + // and returns discovered IQNs. + DiscoverTargetPortal(ctx context.Context, in *DiscoverTargetPortalRequest, opts ...grpc.CallOption) (*DiscoverTargetPortalResponse, error) + // RemoveTargetPortal removes an iSCSI target network address registration. + RemoveTargetPortal(ctx context.Context, in *RemoveTargetPortalRequest, opts ...grpc.CallOption) (*RemoveTargetPortalResponse, error) + // ListTargetPortal lists all currently registered iSCSI target network + // addresses. + ListTargetPortals(ctx context.Context, in *ListTargetPortalsRequest, opts ...grpc.CallOption) (*ListTargetPortalsResponse, error) + // ConnectTarget connects to an iSCSI Target + ConnectTarget(ctx context.Context, in *ConnectTargetRequest, opts ...grpc.CallOption) (*ConnectTargetResponse, error) + // DisconnectTarget disconnects from an iSCSI Target + DisconnectTarget(ctx context.Context, in *DisconnectTargetRequest, opts ...grpc.CallOption) (*DisconnectTargetResponse, error) + // GetTargetDisks returns the disk addresses that correspond to an iSCSI + // target + GetTargetDisks(ctx context.Context, in *GetTargetDisksRequest, opts ...grpc.CallOption) (*GetTargetDisksResponse, error) +} + +type iscsiClient struct { + cc grpc.ClientConnInterface +} + +func NewIscsiClient(cc grpc.ClientConnInterface) IscsiClient { + return &iscsiClient{cc} +} + +func (c *iscsiClient) AddTargetPortal(ctx context.Context, in *AddTargetPortalRequest, opts ...grpc.CallOption) (*AddTargetPortalResponse, error) { + out := new(AddTargetPortalResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/AddTargetPortal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) DiscoverTargetPortal(ctx context.Context, in *DiscoverTargetPortalRequest, opts ...grpc.CallOption) (*DiscoverTargetPortalResponse, error) { + out := new(DiscoverTargetPortalResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/DiscoverTargetPortal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) RemoveTargetPortal(ctx context.Context, in *RemoveTargetPortalRequest, opts ...grpc.CallOption) (*RemoveTargetPortalResponse, error) { + out := new(RemoveTargetPortalResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/RemoveTargetPortal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) ListTargetPortals(ctx context.Context, in *ListTargetPortalsRequest, opts ...grpc.CallOption) (*ListTargetPortalsResponse, error) { + out := new(ListTargetPortalsResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/ListTargetPortals", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) ConnectTarget(ctx context.Context, in *ConnectTargetRequest, opts ...grpc.CallOption) (*ConnectTargetResponse, error) { + out := new(ConnectTargetResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/ConnectTarget", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) DisconnectTarget(ctx context.Context, in *DisconnectTargetRequest, opts ...grpc.CallOption) (*DisconnectTargetResponse, error) { + out := new(DisconnectTargetResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/DisconnectTarget", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) GetTargetDisks(ctx context.Context, in *GetTargetDisksRequest, opts ...grpc.CallOption) (*GetTargetDisksResponse, error) { + out := new(GetTargetDisksResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/GetTargetDisks", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// IscsiServer is the server API for Iscsi service. +type IscsiServer interface { + // AddTargetPortal registers an iSCSI target network address for later + // discovery. + // AddTargetPortal currently does not support selecting different NICs or + // a different iSCSI initiator (e.g a hardware initiator). This means that + // Windows will select the initiator NIC and instance on its own. + AddTargetPortal(context.Context, *AddTargetPortalRequest) (*AddTargetPortalResponse, error) + // DiscoverTargetPortal initiates discovery on an iSCSI target network address + // and returns discovered IQNs. + DiscoverTargetPortal(context.Context, *DiscoverTargetPortalRequest) (*DiscoverTargetPortalResponse, error) + // RemoveTargetPortal removes an iSCSI target network address registration. + RemoveTargetPortal(context.Context, *RemoveTargetPortalRequest) (*RemoveTargetPortalResponse, error) + // ListTargetPortal lists all currently registered iSCSI target network + // addresses. + ListTargetPortals(context.Context, *ListTargetPortalsRequest) (*ListTargetPortalsResponse, error) + // ConnectTarget connects to an iSCSI Target + ConnectTarget(context.Context, *ConnectTargetRequest) (*ConnectTargetResponse, error) + // DisconnectTarget disconnects from an iSCSI Target + DisconnectTarget(context.Context, *DisconnectTargetRequest) (*DisconnectTargetResponse, error) + // GetTargetDisks returns the disk addresses that correspond to an iSCSI + // target + GetTargetDisks(context.Context, *GetTargetDisksRequest) (*GetTargetDisksResponse, error) +} + +// UnimplementedIscsiServer can be embedded to have forward compatible implementations. +type UnimplementedIscsiServer struct { +} + +func (*UnimplementedIscsiServer) AddTargetPortal(ctx context.Context, req *AddTargetPortalRequest) (*AddTargetPortalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddTargetPortal not implemented") +} +func (*UnimplementedIscsiServer) DiscoverTargetPortal(ctx context.Context, req *DiscoverTargetPortalRequest) (*DiscoverTargetPortalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DiscoverTargetPortal not implemented") +} +func (*UnimplementedIscsiServer) RemoveTargetPortal(ctx context.Context, req *RemoveTargetPortalRequest) (*RemoveTargetPortalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveTargetPortal not implemented") +} +func (*UnimplementedIscsiServer) ListTargetPortals(ctx context.Context, req *ListTargetPortalsRequest) (*ListTargetPortalsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListTargetPortals not implemented") +} +func (*UnimplementedIscsiServer) ConnectTarget(ctx context.Context, req *ConnectTargetRequest) (*ConnectTargetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConnectTarget not implemented") +} +func (*UnimplementedIscsiServer) DisconnectTarget(ctx context.Context, req *DisconnectTargetRequest) (*DisconnectTargetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DisconnectTarget not implemented") +} +func (*UnimplementedIscsiServer) GetTargetDisks(ctx context.Context, req *GetTargetDisksRequest) (*GetTargetDisksResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTargetDisks not implemented") +} + +func RegisterIscsiServer(s *grpc.Server, srv IscsiServer) { + s.RegisterService(&_Iscsi_serviceDesc, srv) +} + +func _Iscsi_AddTargetPortal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddTargetPortalRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).AddTargetPortal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/AddTargetPortal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).AddTargetPortal(ctx, req.(*AddTargetPortalRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_DiscoverTargetPortal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DiscoverTargetPortalRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).DiscoverTargetPortal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/DiscoverTargetPortal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).DiscoverTargetPortal(ctx, req.(*DiscoverTargetPortalRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_RemoveTargetPortal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveTargetPortalRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).RemoveTargetPortal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/RemoveTargetPortal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).RemoveTargetPortal(ctx, req.(*RemoveTargetPortalRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_ListTargetPortals_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListTargetPortalsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).ListTargetPortals(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/ListTargetPortals", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).ListTargetPortals(ctx, req.(*ListTargetPortalsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_ConnectTarget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ConnectTargetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).ConnectTarget(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/ConnectTarget", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).ConnectTarget(ctx, req.(*ConnectTargetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_DisconnectTarget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DisconnectTargetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).DisconnectTarget(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/DisconnectTarget", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).DisconnectTarget(ctx, req.(*DisconnectTargetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_GetTargetDisks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTargetDisksRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).GetTargetDisks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/GetTargetDisks", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).GetTargetDisks(ctx, req.(*GetTargetDisksRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Iscsi_serviceDesc = grpc.ServiceDesc{ + ServiceName: "v1alpha1.Iscsi", + HandlerType: (*IscsiServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddTargetPortal", + Handler: _Iscsi_AddTargetPortal_Handler, + }, + { + MethodName: "DiscoverTargetPortal", + Handler: _Iscsi_DiscoverTargetPortal_Handler, + }, + { + MethodName: "RemoveTargetPortal", + Handler: _Iscsi_RemoveTargetPortal_Handler, + }, + { + MethodName: "ListTargetPortals", + Handler: _Iscsi_ListTargetPortals_Handler, + }, + { + MethodName: "ConnectTarget", + Handler: _Iscsi_ConnectTarget_Handler, + }, + { + MethodName: "DisconnectTarget", + Handler: _Iscsi_DisconnectTarget_Handler, + }, + { + MethodName: "GetTargetDisks", + Handler: _Iscsi_GetTargetDisks_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto", +} diff --git a/client/api/iscsi/v1alpha1/api.proto b/client/api/iscsi/v1alpha1/api.proto new file mode 100644 index 00000000..b667f8da --- /dev/null +++ b/client/api/iscsi/v1alpha1/api.proto @@ -0,0 +1,153 @@ +syntax = "proto3"; + +package v1alpha1; + +option go_package = "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1"; + +service Iscsi { + // AddTargetPortal registers an iSCSI target network address for later + // discovery. + // AddTargetPortal currently does not support selecting different NICs or + // a different iSCSI initiator (e.g a hardware initiator). This means that + // Windows will select the initiator NIC and instance on its own. + rpc AddTargetPortal(AddTargetPortalRequest) + returns (AddTargetPortalResponse) {} + + // DiscoverTargetPortal initiates discovery on an iSCSI target network address + // and returns discovered IQNs. + rpc DiscoverTargetPortal(DiscoverTargetPortalRequest) + returns (DiscoverTargetPortalResponse) {} + + // RemoveTargetPortal removes an iSCSI target network address registration. + rpc RemoveTargetPortal(RemoveTargetPortalRequest) + returns (RemoveTargetPortalResponse) {} + + // ListTargetPortal lists all currently registered iSCSI target network + // addresses. + rpc ListTargetPortals(ListTargetPortalsRequest) + returns (ListTargetPortalsResponse) {} + + // ConnectTarget connects to an iSCSI Target + rpc ConnectTarget(ConnectTargetRequest) returns (ConnectTargetResponse) {} + + // DisconnectTarget disconnects from an iSCSI Target + rpc DisconnectTarget(DisconnectTargetRequest) + returns (DisconnectTargetResponse) {} + + // GetTargetDisks returns the disk addresses that correspond to an iSCSI + // target + rpc GetTargetDisks(GetTargetDisksRequest) returns (GetTargetDisksResponse) {} +} + +// TargetPortal is an address and port pair for a specific iSCSI storage +// target. +message TargetPortal { + // iSCSI Target (server) address + string target_address = 1; + + // iSCSI Target port (default iSCSI port is 3260) + uint32 target_port = 2; +} + +message AddTargetPortalRequest { + // iSCSI Target Portal to register in the initiator + TargetPortal target_portal = 1; +} + +message AddTargetPortalResponse { + // Intentionally empty +} + +message DiscoverTargetPortalRequest { + // iSCSI Target Portal on which to initiate discovery + TargetPortal target_portal = 1; +} + +message DiscoverTargetPortalResponse { + // List of discovered IQN addresses + // follows IQN format: iqn.yyyy-mm.naming-authority:unique-name + repeated string iqns = 1; +} + +message RemoveTargetPortalRequest { + // iSCSI Target Portal + TargetPortal target_portal = 1; +} + +message RemoveTargetPortalResponse { + // Intentionally empty +} + +message ListTargetPortalsRequest { + // Intentionally empty +} + +message ListTargetPortalsResponse { + // A list of Target Portals currently registered in the initiator + repeated TargetPortal target_portals = 1; +} + +enum AuthenticationType { + // No authentication is used + NONE = 0; + + // One way CHAP authentication. The target authenticates the initiator. + ONE_WAY_CHAP = 1; + + // Mutual CHAP authentication. The target and initiator authenticate each + // other. + MUTUAL_CHAP = 2; +} + +message ConnectTargetRequest { + // Target portal to which the initiator will connect + TargetPortal target_portal = 1; + + // IQN of the iSCSI Target + string iqn = 2; + + // Connection authentication type, None by default + // + // One Way Chap uses the chap_username and chap_secret + // fields mentioned below to authenticate the initiator. + // + // Mutual Chap uses both the user/secret mentioned below + // and the Initiator Chap Secret to authenticate the target and initiator. + AuthenticationType auth_type = 3; + + // CHAP Username used to authenticate the initiator + string chap_username = 4; + + // CHAP password used to authenticate the initiator + string chap_secret = 5; +} + +message ConnectTargetResponse { + // Intentionally empty +} + +message GetTargetDisksRequest { + // Target portal whose disks will be queried + TargetPortal target_portal = 1; + + // IQN of the iSCSI Target + string iqn = 2; +} + +message GetTargetDisksResponse { + // List composed of disk ids (numbers) that are associated with the + // iSCSI target + repeated string diskIDs = 1; +} + +message DisconnectTargetRequest { + // Target portal from which initiator will disconnect + TargetPortal target_portal = 1; + + // IQN of the iSCSI Target + string iqn = 2; +} + +message DisconnectTargetResponse { + // Intentionally empty +} diff --git a/client/groups/iscsi/v1alpha1/client_generated.go b/client/groups/iscsi/v1alpha1/client_generated.go new file mode 100644 index 00000000..d4e75b61 --- /dev/null +++ b/client/groups/iscsi/v1alpha1/client_generated.go @@ -0,0 +1,80 @@ +// Code generated by csi-proxy-api-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "net" + + "github.com/Microsoft/go-winio" + "github.com/kubernetes-csi/csi-proxy/client" + "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1" + "github.com/kubernetes-csi/csi-proxy/client/apiversion" + "google.golang.org/grpc" +) + +const groupName = "iscsi" + +var version = apiversion.NewVersionOrPanic("v1alpha1") + +type Client struct { + client v1alpha1.IscsiClient + connection *grpc.ClientConn +} + +// NewClient returns a client to make calls to the iscsi API group version v1alpha1. +// It's the caller's responsibility to Close the client when done. +func NewClient() (*Client, error) { + pipePath := client.PipePath(groupName, version) + + connection, err := grpc.Dial(pipePath, + grpc.WithContextDialer(func(context context.Context, s string) (net.Conn, error) { + return winio.DialPipeContext(context, s) + }), + grpc.WithInsecure()) + if err != nil { + return nil, err + } + + client := v1alpha1.NewIscsiClient(connection) + return &Client{ + client: client, + connection: connection, + }, nil +} + +// Close closes the client. It must be called before the client gets GC-ed. +func (w *Client) Close() error { + return w.connection.Close() +} + +// ensures we implement all the required methods +var _ v1alpha1.IscsiClient = &Client{} + +func (w *Client) AddTargetPortal(context context.Context, request *v1alpha1.AddTargetPortalRequest, opts ...grpc.CallOption) (*v1alpha1.AddTargetPortalResponse, error) { + return w.client.AddTargetPortal(context, request, opts...) +} + +func (w *Client) ConnectTarget(context context.Context, request *v1alpha1.ConnectTargetRequest, opts ...grpc.CallOption) (*v1alpha1.ConnectTargetResponse, error) { + return w.client.ConnectTarget(context, request, opts...) +} + +func (w *Client) DisconnectTarget(context context.Context, request *v1alpha1.DisconnectTargetRequest, opts ...grpc.CallOption) (*v1alpha1.DisconnectTargetResponse, error) { + return w.client.DisconnectTarget(context, request, opts...) +} + +func (w *Client) DiscoverTargetPortal(context context.Context, request *v1alpha1.DiscoverTargetPortalRequest, opts ...grpc.CallOption) (*v1alpha1.DiscoverTargetPortalResponse, error) { + return w.client.DiscoverTargetPortal(context, request, opts...) +} + +func (w *Client) GetTargetDisks(context context.Context, request *v1alpha1.GetTargetDisksRequest, opts ...grpc.CallOption) (*v1alpha1.GetTargetDisksResponse, error) { + return w.client.GetTargetDisks(context, request, opts...) +} + +func (w *Client) ListTargetPortals(context context.Context, request *v1alpha1.ListTargetPortalsRequest, opts ...grpc.CallOption) (*v1alpha1.ListTargetPortalsResponse, error) { + return w.client.ListTargetPortals(context, request, opts...) +} + +func (w *Client) RemoveTargetPortal(context context.Context, request *v1alpha1.RemoveTargetPortalRequest, opts ...grpc.CallOption) (*v1alpha1.RemoveTargetPortalResponse, error) { + return w.client.RemoveTargetPortal(context, request, opts...) +} diff --git a/cmd/csi-proxy/main.go b/cmd/csi-proxy/main.go index ff004a9f..a5b95311 100644 --- a/cmd/csi-proxy/main.go +++ b/cmd/csi-proxy/main.go @@ -5,12 +5,14 @@ import ( diskapi "github.com/kubernetes-csi/csi-proxy/internal/os/disk" filesystemapi "github.com/kubernetes-csi/csi-proxy/internal/os/filesystem" + iscsiapi "github.com/kubernetes-csi/csi-proxy/internal/os/iscsi" smbapi "github.com/kubernetes-csi/csi-proxy/internal/os/smb" sysapi "github.com/kubernetes-csi/csi-proxy/internal/os/system" volumeapi "github.com/kubernetes-csi/csi-proxy/internal/os/volume" "github.com/kubernetes-csi/csi-proxy/internal/server" disksrv "github.com/kubernetes-csi/csi-proxy/internal/server/disk" filesystemsrv "github.com/kubernetes-csi/csi-proxy/internal/server/filesystem" + iscsisrv "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi" smbsrv "github.com/kubernetes-csi/csi-proxy/internal/server/smb" syssrv "github.com/kubernetes-csi/csi-proxy/internal/server/system" srvtypes "github.com/kubernetes-csi/csi-proxy/internal/server/types" @@ -84,12 +86,18 @@ func apiGroups() ([]srvtypes.APIGroup, error) { return []srvtypes.APIGroup{}, err } + iscsisrv, err := iscsisrv.NewServer(iscsiapi.New()) + if err != nil { + return []srvtypes.APIGroup{}, err + } + return []srvtypes.APIGroup{ fssrv, disksrv, volumesrv, smbsrv, syssrv, + iscsisrv, }, nil } diff --git a/go.mod b/go.mod index d0f2bf72..5556822d 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ replace ( require ( github.com/Microsoft/go-winio v0.4.14 github.com/golang/protobuf v1.4.1 + github.com/google/go-cmp v0.5.0 github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 github.com/kubernetes-csi/csi-proxy/client v0.0.0-00010101000000-000000000000 github.com/pkg/errors v0.8.1 @@ -25,6 +26,7 @@ require ( golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 golang.org/x/text v0.3.2 // indirect google.golang.org/grpc v1.27.1 + google.golang.org/protobuf v1.25.0 k8s.io/gengo v0.0.0-00010101000000-000000000000 k8s.io/klog v1.0.0 ) diff --git a/integrationtests/iscsi_ps_scripts.go b/integrationtests/iscsi_ps_scripts.go new file mode 100644 index 00000000..dbaa7c39 --- /dev/null +++ b/integrationtests/iscsi_ps_scripts.go @@ -0,0 +1,184 @@ +package integrationtests + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "os/exec" + "testing" +) + +func installIscsiTarget() error { + _, err := runPowershellScript(IscsiTargetInstallScript) + if err != nil { + return fmt.Errorf("failed installing iSCSI target. err=%v", err) + } + + return nil +} + +const IscsiTargetInstallScript = ` +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +# Install iSCSI Target +Install-WindowsFeature FS-iSCSITarget-Server + +# Setup for loopback usage +Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\iSCSI Target" -Name AllowLoopBack -Value 1 +Restart-Service WinTarget +` + +type IscsiSetupConfig struct { + Iqn string `json:"iqn"` + Ip string `json:"ip"` +} + +const IscsiEnvironmentSetupScript = ` +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$targetName = "%s" + +# Get local IPv4 (e.g. 10.30.1.15, not 127.0.0.1) +$address = $(Get-NetIPAddress | Where-Object { $_.InterfaceAlias -eq "Ethernet" -and $_.AddressFamily -eq "IPv4" }).IPAddress + +# Create virtual disk in RAM +New-IscsiVirtualDisk -Path "ramdisk:scratch-${targetName}.vhdx" -Size 100MB | Out-Null + +# Create a target that allows all initiator IQNs and map a disk to the new target +$target = New-IscsiServerTarget -TargetName $targetName -InitiatorIds @("Iqn:*") +Add-IscsiVirtualDiskTargetMapping -TargetName $targetName -DevicePath "ramdisk:scratch-${targetName}.vhdx" | Out-Null + +$output = @{ + "iqn" = "$($target.TargetIqn)" + "ip" = $address +} + +$output | ConvertTo-Json | Write-Output +` + +const IscsiSetChapScript = ` +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$targetName = "%s" +$username = "%s" +$password = "%s" +$securestring = ConvertTo-SecureString -String $password -AsPlainText -Force +$chap = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($username, $securestring) +Set-IscsiServerTarget -TargetName $targetName -EnableChap $true -Chap $chap +` + +func setChap(targetName string, username string, password string) error { + script := fmt.Sprintf(IscsiSetChapScript, targetName, username, password) + _, err := runPowershellScript(script) + if err != nil { + return fmt.Errorf("failed setting CHAP on iSCSI target=%v. err=%v", targetName, err) + } + + return nil +} + +const IscsiSetReverseChapScript = ` +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$targetName = "%s" +$password = "%s" +$username = "doesnt-matter" +$securestring = ConvertTo-SecureString -String $password -AsPlainText -Force + +# Windows initiator does not uses the username for mutual authentication +$chap = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($username, $securestring) +Set-IscsiServerTarget -TargetName $targetName -EnableReverseChap $true -ReverseChap $chap +` + +func setReverseChap(targetName string, password string) error { + script := fmt.Sprintf(IscsiSetReverseChapScript, targetName, password) + _, err := runPowershellScript(script) + if err != nil { + return fmt.Errorf("failed setting reverse CHAP on iSCSI target=%v. err=%v", targetName, err) + } + + return nil +} + +func cleanup(t *testing.T) error { + _, err := runPowershellScript(IscsiCleanupScript) + if err != nil { + msg := fmt.Sprintf("failed cleaning up environment. err=%v", err) + t.Fatal(msg) + // exits function + } + + return nil +} + +const IscsiCleanupScript = ` +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +# Clean initiator +Get-Disk | Where-Object {$_.Bustype -eq "iSCSI"} | Set-Disk -IsOffline:$true +Get-IscsiTarget | Disconnect-IscsiTarget -Confirm:$false +Get-IscsiTargetPortal | Remove-IscsiTargetPortal -confirm:$false + +# Clean target +Get-IscsiServerTarget | Remove-IscsiServerTarget +Get-IscsiVirtualDisk | Remove-IscsiVirtualDisk + +# Stop iSCSI initiator +Get-Service "MsiSCSI" | Stop-Service +` + +func writeTempFile(text string, extension string) (string, error) { + pattern := fmt.Sprintf("*.%s", extension) + tempfile, err := ioutil.TempFile(os.TempDir(), pattern) + if err != nil { + return "", fmt.Errorf("failed creating temp file pattern=%v: %w", pattern, err) + } + + defer tempfile.Close() + + _, err = tempfile.WriteString(text) + if err != nil { + return "", fmt.Errorf("failed writing to temp file name=%v: %w", tempfile.Name(), err) + } + + return tempfile.Name(), nil +} + +func runPowershellScript(script string) (string, error) { + path, err := writeTempFile(script, "ps1") + if err != nil { + return "", err + } + + defer os.Remove(path) + + cmd := exec.Command("powershell", "-File", path) + out, err := cmd.CombinedOutput() + if err != nil { + return "", fmt.Errorf("error running powershell script. path %s, output: %s, err: %w", path, string(out), err) + } + + return string(out), nil +} + +func setupEnv(targetName string) (*IscsiSetupConfig, error) { + script := fmt.Sprintf(IscsiEnvironmentSetupScript, targetName) + out, err := runPowershellScript(script) + if err != nil { + return nil, fmt.Errorf("failed setting up environment. err=%v", err) + } + + config := IscsiSetupConfig{} + err = json.Unmarshal([]byte(out), &config) + if err != nil { + return nil, err + } + + return &config, nil +} diff --git a/integrationtests/iscsi_test.go b/integrationtests/iscsi_test.go new file mode 100644 index 00000000..504144e3 --- /dev/null +++ b/integrationtests/iscsi_test.go @@ -0,0 +1,365 @@ +package integrationtests + +// Needs to run the test in a VM with a local iSCSI target. +// See iscsi_test_setup.ps1 script + +import ( + "context" + "fmt" + "testing" + + disk_api "github.com/kubernetes-csi/csi-proxy/client/api/disk/v1beta2" + iscsi_api "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1" + system_api "github.com/kubernetes-csi/csi-proxy/client/api/system/v1alpha1" + disk_client "github.com/kubernetes-csi/csi-proxy/client/groups/disk/v1beta2" + iscsi_client "github.com/kubernetes-csi/csi-proxy/client/groups/iscsi/v1alpha1" + system_client "github.com/kubernetes-csi/csi-proxy/client/groups/system/v1alpha1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const defaultIscsiPort = 3260 +const defaultProtoPort = 0 // default value when port is not set + +func TestIscsiAPIGroup(t *testing.T) { + skipTestOnCondition(t, !shouldRunIscsiTests()) + + err := installIscsiTarget() + require.NoError(t, err, "Failed installing iSCSI target") + + t.Run("List/Add/Remove TargetPortal (Port=3260)", func(t *testing.T) { + targetPortalTest(t, defaultIscsiPort) + }) + + t.Run("List/Add/Remove TargetPortal (Port not mentioned, effectively 3260)", func(t *testing.T) { + targetPortalTest(t, defaultProtoPort) + }) + + t.Run("Discover Target and Connect/Disconnect (No CHAP)", func(t *testing.T) { + targetTest(t) + }) + + t.Run("Discover Target and Connect/Disconnect (CHAP)", func(t *testing.T) { + targetChapTest(t) + }) + + t.Run("Discover Target and Connect/Disconnect (Mutual CHAP)", func(t *testing.T) { + targetMutualChapTest(t) + }) + + t.Run("Full flow", func(t *testing.T) { + e2e_test(t) + }) + +} + +func e2e_test(t *testing.T) { + config, err := setupEnv("e2e") + assert.NoError(t, err) + + defer cleanup(t) + + iscsi, err := iscsi_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, iscsi.Close()) }() + + disk, err := disk_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, disk.Close()) }() + + system, err := system_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, system.Close()) }() + + startReq := &system_api.StartServiceRequest{Name: "MSiSCSI"} + _, err = system.StartService(context.TODO(), startReq) + require.NoError(t, err) + + tp := &iscsi_api.TargetPortal{ + TargetAddress: config.Ip, + TargetPort: defaultIscsiPort, + } + + addTpReq := &iscsi_api.AddTargetPortalRequest{ + TargetPortal: tp, + } + _, err = iscsi.AddTargetPortal(context.Background(), addTpReq) + assert.Nil(t, err) + + discReq := &iscsi_api.DiscoverTargetPortalRequest{TargetPortal: tp} + discResp, err := iscsi.DiscoverTargetPortal(context.TODO(), discReq) + if assert.Nil(t, err) { + assert.Contains(t, discResp.Iqns, config.Iqn) + } + + connectReq := &iscsi_api.ConnectTargetRequest{TargetPortal: tp, Iqn: config.Iqn} + _, err = iscsi.ConnectTarget(context.TODO(), connectReq) + assert.Nil(t, err) + + tgtDisksReq := &iscsi_api.GetTargetDisksRequest{TargetPortal: tp, Iqn: config.Iqn} + tgtDisksResp, err := iscsi.GetTargetDisks(context.TODO(), tgtDisksReq) + require.Nil(t, err) + require.Len(t, tgtDisksResp.DiskIDs, 1) + + diskId := tgtDisksResp.DiskIDs[0] + + attachReq := &disk_api.SetAttachStateRequest{DiskID: diskId, IsOnline: true} + _, err = disk.SetAttachState(context.TODO(), attachReq) + require.Nil(t, err) + + partReq := &disk_api.PartitionDiskRequest{DiskID: diskId} + _, err = disk.PartitionDisk(context.TODO(), partReq) + assert.Nil(t, err) + + detachReq := &disk_api.SetAttachStateRequest{DiskID: diskId, IsOnline: false} + _, err = disk.SetAttachState(context.TODO(), detachReq) + assert.Nil(t, err) +} + +func targetTest(t *testing.T) { + config, err := setupEnv("target") + assert.NoError(t, err) + + defer cleanup(t) + + client, err := iscsi_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, client.Close()) }() + + system, err := system_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, system.Close()) }() + + startReq := &system_api.StartServiceRequest{Name: "MSiSCSI"} + _, err = system.StartService(context.TODO(), startReq) + require.NoError(t, err) + + tp := &iscsi_api.TargetPortal{ + TargetAddress: config.Ip, + TargetPort: defaultIscsiPort, + } + + addTpReq := &iscsi_api.AddTargetPortalRequest{ + TargetPortal: tp, + } + _, err = client.AddTargetPortal(context.Background(), addTpReq) + assert.Nil(t, err) + + discReq := &iscsi_api.DiscoverTargetPortalRequest{TargetPortal: tp} + discResp, err := client.DiscoverTargetPortal(context.TODO(), discReq) + if assert.Nil(t, err) { + assert.Contains(t, discResp.Iqns, config.Iqn) + } + + connectReq := &iscsi_api.ConnectTargetRequest{TargetPortal: tp, Iqn: config.Iqn} + _, err = client.ConnectTarget(context.TODO(), connectReq) + assert.Nil(t, err) + + disconReq := &iscsi_api.DisconnectTargetRequest{TargetPortal: tp, Iqn: config.Iqn} + _, err = client.DisconnectTarget(context.TODO(), disconReq) + assert.Nil(t, err) +} + +func targetChapTest(t *testing.T) { + const targetName = "chapTarget" + const username = "someuser" + const password = "verysecretpass" + + config, err := setupEnv(targetName) + require.NoError(t, err) + + defer cleanup(t) + + err = setChap(targetName, username, password) + require.NoError(t, err) + + client, err := iscsi_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, client.Close()) }() + + system, err := system_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, system.Close()) }() + + startReq := &system_api.StartServiceRequest{Name: "MSiSCSI"} + _, err = system.StartService(context.TODO(), startReq) + require.NoError(t, err) + + tp := &iscsi_api.TargetPortal{ + TargetAddress: config.Ip, + TargetPort: defaultIscsiPort, + } + + addTpReq := &iscsi_api.AddTargetPortalRequest{ + TargetPortal: tp, + } + _, err = client.AddTargetPortal(context.Background(), addTpReq) + assert.Nil(t, err) + + discReq := &iscsi_api.DiscoverTargetPortalRequest{TargetPortal: tp} + discResp, err := client.DiscoverTargetPortal(context.TODO(), discReq) + if assert.Nil(t, err) { + assert.Contains(t, discResp.Iqns, config.Iqn) + } + + connectReq := &iscsi_api.ConnectTargetRequest{ + TargetPortal: tp, + Iqn: config.Iqn, + ChapUsername: username, + ChapSecret: password, + AuthType: iscsi_api.AuthenticationType_ONE_WAY_CHAP, + } + _, err = client.ConnectTarget(context.TODO(), connectReq) + assert.Nil(t, err) + + disconReq := &iscsi_api.DisconnectTargetRequest{TargetPortal: tp, Iqn: config.Iqn} + _, err = client.DisconnectTarget(context.TODO(), disconReq) + assert.Nil(t, err) +} + +func targetMutualChapTest(t *testing.T) { + const targetName = "mutualChapTarget" + const username = "anotheruser" + const password = "broccoli-man" + const reverse_password = "reversssssssse" + + config, err := setupEnv(targetName) + require.NoError(t, err) + + defer cleanup(t) + + err = setChap(targetName, username, password) + require.NoError(t, err) + + err = setReverseChap(targetName, reverse_password) + require.NoError(t, err) + + client, err := iscsi_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, client.Close()) }() + + system, err := system_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, system.Close()) }() + + startReq := &system_api.StartServiceRequest{Name: "MSiSCSI"} + _, err = system.StartService(context.TODO(), startReq) + require.NoError(t, err) + + tp := &iscsi_api.TargetPortal{ + TargetAddress: config.Ip, + TargetPort: defaultIscsiPort, + } + + addTpReq := &iscsi_api.AddTargetPortalRequest{ + TargetPortal: tp, + } + _, err = client.AddTargetPortal(context.Background(), addTpReq) + assert.Nil(t, err) + + discReq := &iscsi_api.DiscoverTargetPortalRequest{TargetPortal: tp} + discResp, err := client.DiscoverTargetPortal(context.TODO(), discReq) + if assert.Nil(t, err) { + assert.Contains(t, discResp.Iqns, config.Iqn) + } + + connectReq := &iscsi_api.ConnectTargetRequest{ + TargetPortal: tp, + Iqn: config.Iqn, + ChapUsername: username, + ChapSecret: password, + AuthType: iscsi_api.AuthenticationType_MUTUAL_CHAP, + } + + // TODO: Replace this with the corresponding csi-proxy API when add it + // Try using a wrong initiator password and expect error + out, err := runPowershellCmd(`Set-IscsiChapSecret -ChapSecret "made-up-pass"`) + require.NoErrorf(t, err, "Cannot set initiator chap out=%v", out) + + _, err = client.ConnectTarget(context.TODO(), connectReq) + assert.NotNil(t, err) + + // TODO: Replace this with the corresponding csi-proxy API when add it + out, err = runPowershellCmd(fmt.Sprintf(`Set-IscsiChapSecret -ChapSecret "%s"`, + reverse_password)) + require.NoErrorf(t, err, "Cannot set initiator chap out=%v", out) + + _, err = client.ConnectTarget(context.TODO(), connectReq) + assert.Nil(t, err) + + disconReq := &iscsi_api.DisconnectTargetRequest{TargetPortal: tp, Iqn: config.Iqn} + _, err = client.DisconnectTarget(context.TODO(), disconReq) + assert.Nil(t, err) +} + +func targetPortalTest(t *testing.T, port uint32) { + config, err := setupEnv(fmt.Sprintf("targetportal-%d", port)) + assert.NoError(t, err) + + defer cleanup(t) + + client, err := iscsi_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, client.Close()) }() + + system, err := system_client.NewClient() + require.Nil(t, err) + + defer func() { assert.NoError(t, system.Close()) }() + + startReq := &system_api.StartServiceRequest{Name: "MSiSCSI"} + _, err = system.StartService(context.TODO(), startReq) + require.NoError(t, err) + + tp := &iscsi_api.TargetPortal{ + TargetAddress: config.Ip, + TargetPort: port, + } + + listReq := &iscsi_api.ListTargetPortalsRequest{} + + listResp, err := client.ListTargetPortals(context.Background(), listReq) + if assert.Nil(t, err) { + assert.Len(t, listResp.TargetPortals, 0, + "Expect no registered target portals") + } + + addTpReq := &iscsi_api.AddTargetPortalRequest{TargetPortal: tp} + _, err = client.AddTargetPortal(context.Background(), addTpReq) + assert.Nil(t, err) + + // Port 0 (unset) is handled as the default iSCSI port + expectedPort := port + if expectedPort == 0 { + expectedPort = defaultIscsiPort + } + + gotListResp, err := client.ListTargetPortals(context.Background(), listReq) + if assert.Nil(t, err) { + assert.Len(t, gotListResp.TargetPortals, 1) + assert.Equal(t, gotListResp.TargetPortals[0].TargetPort, expectedPort) + assert.Equal(t, gotListResp.TargetPortals[0].TargetAddress, tp.TargetAddress) + } + + remReq := &iscsi_api.RemoveTargetPortalRequest{ + TargetPortal: tp, + } + _, err = client.RemoveTargetPortal(context.Background(), remReq) + assert.Nil(t, err) + + listResp, err = client.ListTargetPortals(context.Background(), listReq) + if assert.Nil(t, err) { + assert.Len(t, listResp.TargetPortals, 0, + "Expect no registered target portals after delete") + } +} diff --git a/integrationtests/utils.go b/integrationtests/utils.go index 3d9d064b..5c739974 100644 --- a/integrationtests/utils.go +++ b/integrationtests/utils.go @@ -144,3 +144,11 @@ func skipTestOnCondition(t *testing.T, condition bool) { t.Skip("Skipping test") } } + +// returns true if ENABLE_ISCSI_TESTS is set to "TRUE" +// used to skip iSCSI tests as they affect the test machine +// e.g. install an iSCSI target, format a disk, etc. +// Take care to use disposable clean VMs for tests +func shouldRunIscsiTests() bool { + return os.Getenv("ENABLE_ISCSI_TESTS") == "TRUE" +} diff --git a/internal/os/iscsi/api.go b/internal/os/iscsi/api.go new file mode 100644 index 00000000..80e02f97 --- /dev/null +++ b/internal/os/iscsi/api.go @@ -0,0 +1,190 @@ +package iscsi + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" +) + +// Implements the iSCSI OS API calls. All code here should be very simple +// pass-through to the OS APIs. Any logic around the APIs should go in +// internal/server/iscsi/server.go so that logic can be easily unit-tested +// without requiring specific OS environments. + +type APIImplementor struct{} + +func New() APIImplementor { + return APIImplementor{} +} + +func (APIImplementor) AddTargetPortal(portal *TargetPortal) error { + cmdLine := fmt.Sprintf( + `New-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} ` + + `-TargetPortalPortNumber ${Env:iscsi_tp_port}`) + cmd := exec.Command("powershell.exe", "/c", cmdLine) + cmd.Env = append(os.Environ(), + fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) + + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("error adding target portal. cmd %s, output: %s, err: %v", cmdLine, string(out), err) + } + + return nil +} + +func (APIImplementor) DiscoverTargetPortal(portal *TargetPortal) ([]string, error) { + // ConvertTo-Json is not part of the pipeline because powershell converts an + // array with one element to a single element + cmdLine := fmt.Sprintf( + `ConvertTo-Json -InputObject @(Get-IscsiTargetPortal -TargetPortalAddress ` + + `${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port} | ` + + `Get-IscsiTarget | Select-Object -ExpandProperty NodeAddress)`) + cmd := exec.Command("powershell.exe", "/c", cmdLine) + cmd.Env = append(os.Environ(), + fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) + + out, err := cmd.CombinedOutput() + if err != nil { + return nil, fmt.Errorf("error discovering target portal. cmd: %s, output: %s, err: %w", cmdLine, string(out), err) + } + + var iqns []string + err = json.Unmarshal(out, &iqns) + if err != nil { + return nil, fmt.Errorf("failed parsing iqn list. cmd: %s output: %s, err: %w", cmdLine, string(out), err) + } + + return iqns, nil +} + +func (APIImplementor) ListTargetPortals() ([]TargetPortal, error) { + cmdLine := fmt.Sprintf( + `ConvertTo-Json -InputObject @(Get-IscsiTargetPortal | ` + + `Select-Object TargetPortalAddress, TargetPortalPortNumber)`) + + cmd := exec.Command("powershell.exe", "/c", cmdLine) + out, err := cmd.CombinedOutput() + if err != nil { + return nil, fmt.Errorf("error listing target portals. cmd %s, output: %s, err: %w", cmdLine, string(out), err) + } + + var portals []TargetPortal + err = json.Unmarshal(out, &portals) + if err != nil { + return nil, fmt.Errorf("failed parsing target portal list. cmd: %s output: %s, err: %w", cmdLine, string(out), err) + } + + return portals, nil +} + +func (APIImplementor) RemoveTargetPortal(portal *TargetPortal) error { + cmdLine := fmt.Sprintf( + `Get-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} ` + + `-TargetPortalPortNumber ${Env:iscsi_tp_port} | Remove-IscsiTargetPortal ` + + `-Confirm:$false`) + + cmd := exec.Command("powershell.exe", "/c", cmdLine) + cmd.Env = append(os.Environ(), + fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) + + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("error removing target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) + } + + return nil +} + +func (APIImplementor) ConnectTarget(portal *TargetPortal, iqn string, + authType string, chapUser string, chapSecret string) error { + // Not using InputObject as Connect-IscsiTarget's InputObject does not work. + // This is due to being a static WMI method together with a bug in the + // powershell version of the API. + cmdLine := fmt.Sprintf( + `Connect-IscsiTarget -TargetPortalAddress ${Env:iscsi_tp_address}` + + ` -TargetPortalPortNumber ${Env:iscsi_tp_port} -NodeAddress ${Env:iscsi_target_iqn}` + + ` -AuthenticationType ${Env:iscsi_auth_type}`) + + if chapUser != "" { + cmdLine += fmt.Sprintf(` -ChapUsername ${Env:iscsi_chap_user}`) + } + + if chapSecret != "" { + cmdLine += fmt.Sprintf(` -ChapSecret ${Env:iscsi_chap_secret}`) + } + + cmd := exec.Command("powershell.exe", "/c", cmdLine) + cmd.Env = append(os.Environ(), + fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port), + fmt.Sprintf("iscsi_target_iqn=%s", iqn), + fmt.Sprintf("iscsi_auth_type=%s", authType), + fmt.Sprintf("iscsi_chap_user=%s", chapUser), + fmt.Sprintf("iscsi_chap_secret=%s", chapSecret), + ) + + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("error connecting to target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) + } + + return nil +} + +func (APIImplementor) DisconnectTarget(portal *TargetPortal, iqn string) error { + // Using InputObject instead of pipe to verify input is not empty + cmdLine := fmt.Sprintf( + `Disconnect-IscsiTarget -InputObject (Get-IscsiTargetPortal ` + + `-TargetPortalAddress ${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port} ` + + ` | Get-IscsiTarget | Where-Object { $_.NodeAddress -eq ${Env:iscsi_target_iqn} }) ` + + `-Confirm:$false`) + + cmd := exec.Command("powershell.exe", "/c", cmdLine) + cmd.Env = append(os.Environ(), + fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port), + fmt.Sprintf("iscsi_target_iqn=%s", iqn)) + + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("error disconnecting from target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) + } + + return nil +} + +func (APIImplementor) GetTargetDisks(portal *TargetPortal, iqn string) ([]string, error) { + // Converting DiskNumber to string for compatibility with disk api group + // Not using pipeline in order to validate that items are non-empty + cmdLine := fmt.Sprintf( + `$ErrorActionPreference = "Stop"; ` + + `$tp = Get-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port}; ` + + `$t = $tp | Get-IscsiTarget | Where-Object { $_.NodeAddress -eq ${Env:iscsi_target_iqn} }; ` + + `$c = Get-IscsiConnection -IscsiTarget $t; ` + + `$ids = $c | Get-Disk | Select -ExpandProperty Number | Out-String -Stream; ` + + `ConvertTo-Json -InputObject @($ids)`) + + cmd := exec.Command("powershell.exe", "/c", cmdLine) + cmd.Env = append(os.Environ(), + fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port), + fmt.Sprintf("iscsi_target_iqn=%s", iqn)) + + out, err := cmd.CombinedOutput() + if err != nil { + return nil, fmt.Errorf("error getting target disks. cmd %s, output: %s, err: %w", cmdLine, string(out), err) + } + + var ids []string + err = json.Unmarshal(out, &ids) + if err != nil { + return nil, fmt.Errorf("error parsing iqn target disks. cmd: %s output: %s, err: %w", cmdLine, string(out), err) + } + + return ids, nil +} diff --git a/internal/os/iscsi/types.go b/internal/os/iscsi/types.go new file mode 100644 index 00000000..c8a7dc98 --- /dev/null +++ b/internal/os/iscsi/types.go @@ -0,0 +1,9 @@ +package iscsi + +// TargetPortal is an address and port pair for a specific iSCSI storage +// target. +// JSON field names are the WMI MSFT_iSCSITargetPortal field names. +type TargetPortal struct { + Address string `json:"TargetPortalAddress"` + Port uint32 `json:"TargetPortalPortNumber"` +} diff --git a/internal/server/iscsi/api_group_generated.go b/internal/server/iscsi/api_group_generated.go new file mode 100644 index 00000000..a950065e --- /dev/null +++ b/internal/server/iscsi/api_group_generated.go @@ -0,0 +1,27 @@ +// Code generated by csi-proxy-api-gen. DO NOT EDIT. + +package iscsi + +import ( + "github.com/kubernetes-csi/csi-proxy/client/apiversion" + "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal" + "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal/v1alpha1" + srvtypes "github.com/kubernetes-csi/csi-proxy/internal/server/types" +) + +const name = "iscsi" + +// ensure the server defines all the required methods +var _ internal.ServerInterface = &Server{} + +func (s *Server) VersionedAPIs() []*srvtypes.VersionedAPI { + v1alpha1Server := v1alpha1.NewVersionedServer(s) + + return []*srvtypes.VersionedAPI{ + { + Group: name, + Version: apiversion.NewVersionOrPanic("v1alpha1"), + Registrant: v1alpha1Server.Register, + }, + } +} diff --git a/internal/server/iscsi/internal/conversion_test.go b/internal/server/iscsi/internal/conversion_test.go new file mode 100644 index 00000000..699511da --- /dev/null +++ b/internal/server/iscsi/internal/conversion_test.go @@ -0,0 +1,61 @@ +package internal_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1" + "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal" + v1alpha1_internal "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal/v1alpha1" + "google.golang.org/protobuf/testing/protocmp" +) + +func TestListTargetPortals_Conversion(t *testing.T) { + testCases := []struct { + in *internal.ListTargetPortalsResponse + wantOut *v1alpha1.ListTargetPortalsResponse + wantErr bool + }{ + { + in: &internal.ListTargetPortalsResponse{ + TargetPortals: []*internal.TargetPortal{{TargetPort: 3260, TargetAddress: "test.iqn"}}, + }, + wantOut: &v1alpha1.ListTargetPortalsResponse{ + TargetPortals: []*v1alpha1.TargetPortal{{TargetPort: 3260, TargetAddress: "test.iqn"}}, + }, + wantErr: false, + }, + { + in: &internal.ListTargetPortalsResponse{ + TargetPortals: []*internal.TargetPortal{{TargetPort: 3260, TargetAddress: "test.iqn"}, + {TargetPort: 1000, TargetAddress: "test.iqn.2"}, + }, + }, + wantOut: &v1alpha1.ListTargetPortalsResponse{ + TargetPortals: []*v1alpha1.TargetPortal{{TargetPort: 3260, TargetAddress: "test.iqn"}, + {TargetPort: 1000, TargetAddress: "test.iqn.2"}, + }, + }, + wantErr: false, + }, + { + in: &internal.ListTargetPortalsResponse{}, + wantOut: &v1alpha1.ListTargetPortalsResponse{}, + wantErr: false, + }, + } + + for _, tc := range testCases { + got := v1alpha1.ListTargetPortalsResponse{} + err := v1alpha1_internal.Convert_internal_ListTargetPortalsResponse_To_v1alpha1_ListTargetPortalsResponse(tc.in, &got) + if tc.wantErr && err == nil { + t.Errorf("Expected error but returned a nil error") + } + if !tc.wantErr && err != nil { + t.Errorf("Expected no errors but returned error: %s", err) + } + if diff := cmp.Diff(tc.wantOut, got, protocmp.Transform()); diff != "" { + t.Errorf("Returned unexpected difference between conversion (-want +got):\n%s", diff) + } + } +} diff --git a/internal/server/iscsi/internal/types.go b/internal/server/iscsi/internal/types.go new file mode 100644 index 00000000..6abb0239 --- /dev/null +++ b/internal/server/iscsi/internal/types.go @@ -0,0 +1,110 @@ +package internal + +type AddTargetPortalRequest struct { + // iSCSI Target Portal to register in the initiator + TargetPortal *TargetPortal +} + +type AddTargetPortalResponse struct { + // Intentionally empty +} + +type AuthenticationType uint32 + +const ( + // No authentication is used + NONE = 0 + + // One way CHAP authentication. The target authenticates the initiator. + ONE_WAY_CHAP = 1 + + // Mutual CHAP authentication. The target and initiator authenticate each + // other. + MUTUAL_CHAP = 2 +) + +type ConnectTargetRequest struct { + // Target portal to which the initiator will connect. + TargetPortal *TargetPortal + + // IQN of the iSCSI Target + Iqn string + + // Connection authentication type, None by default + // + // One Way Chap uses the chap_username and chap_secret + // fields mentioned below to authenticate the initiator. + // + // Mutual Chap uses both the user/secret mentioned below + // and the Initiator Chap Secret to authenticate the target and initiator. + AuthType AuthenticationType + + // CHAP Username used to authenticate the initiator + ChapUsername string + + // CHAP password used to authenticate the initiator + ChapSecret string +} + +type ConnectTargetResponse struct { + // Intentionally empty +} + +type DisconnectTargetRequest struct { + // Target portal from which initiator will disconnect + TargetPortal *TargetPortal + // IQN of the iSCSI Target + Iqn string +} + +type DisconnectTargetResponse struct { + // Intentionally empty +} + +type DiscoverTargetPortalRequest struct { + // iSCSI Target Portal on which to initiate discovery + TargetPortal *TargetPortal +} + +type DiscoverTargetPortalResponse struct { + // List of discovered IQN addresses + // follows IQN format: iqn.yyyy-mm.naming-authority:unique-name + Iqns []string +} + +type GetTargetDisksRequest struct { + // Target portal whose disks will be queried + TargetPortal *TargetPortal + // IQN of the iSCSI Target + Iqn string +} + +type GetTargetDisksResponse struct { + // List composed of disk ids (numbers) that are associated with the + // iSCSI target + DiskIDs []string +} + +type ListTargetPortalsRequest struct { +} + +type ListTargetPortalsResponse struct { + // A list of Target Portals currently registered in the initiator + TargetPortals []*TargetPortal +} + +type RemoveTargetPortalRequest struct { + // iSCSI Target Portal + TargetPortal *TargetPortal +} + +type RemoveTargetPortalResponse struct { + // Intentionally empty +} + +type TargetPortal struct { + // iSCSI Target (server) address + TargetAddress string + // iSCSI Target port (default iSCSI port is 3260) + TargetPort uint32 +} diff --git a/internal/server/iscsi/internal/types_generated.go b/internal/server/iscsi/internal/types_generated.go new file mode 100644 index 00000000..6c2be21d --- /dev/null +++ b/internal/server/iscsi/internal/types_generated.go @@ -0,0 +1,25 @@ +// Code generated by csi-proxy-api-gen. DO NOT EDIT. + +package internal + +import ( + "context" + + "github.com/kubernetes-csi/csi-proxy/client/apiversion" + "google.golang.org/grpc" +) + +type VersionedAPI interface { + Register(grpcServer *grpc.Server) +} + +// All the functions this group's server needs to define. +type ServerInterface interface { + AddTargetPortal(context.Context, *AddTargetPortalRequest, apiversion.Version) (*AddTargetPortalResponse, error) + ConnectTarget(context.Context, *ConnectTargetRequest, apiversion.Version) (*ConnectTargetResponse, error) + DisconnectTarget(context.Context, *DisconnectTargetRequest, apiversion.Version) (*DisconnectTargetResponse, error) + DiscoverTargetPortal(context.Context, *DiscoverTargetPortalRequest, apiversion.Version) (*DiscoverTargetPortalResponse, error) + GetTargetDisks(context.Context, *GetTargetDisksRequest, apiversion.Version) (*GetTargetDisksResponse, error) + ListTargetPortals(context.Context, *ListTargetPortalsRequest, apiversion.Version) (*ListTargetPortalsResponse, error) + RemoveTargetPortal(context.Context, *RemoveTargetPortalRequest, apiversion.Version) (*RemoveTargetPortalResponse, error) +} diff --git a/internal/server/iscsi/internal/v1alpha1/conversion.go b/internal/server/iscsi/internal/v1alpha1/conversion.go new file mode 100644 index 00000000..5d163b29 --- /dev/null +++ b/internal/server/iscsi/internal/v1alpha1/conversion.go @@ -0,0 +1,24 @@ +package v1alpha1 + +import ( + "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1" + "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal" +) + +// Add manual conversion functions here to override automatic conversion functions + +func Convert_internal_ListTargetPortalsResponse_To_v1alpha1_ListTargetPortalsResponse(in *internal.ListTargetPortalsResponse, out *v1alpha1.ListTargetPortalsResponse) error { + if in.TargetPortals != nil { + in, out := &in.TargetPortals, &out.TargetPortals + *out = make([]*v1alpha1.TargetPortal, len(*in)) + for i := range *in { + (*out)[i] = new(v1alpha1.TargetPortal) + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*&(*in)[i], *&(*out)[i]); err != nil { + return err + } + } + } else { + out.TargetPortals = nil + } + return nil +} diff --git a/internal/server/iscsi/internal/v1alpha1/conversion_generated.go b/internal/server/iscsi/internal/v1alpha1/conversion_generated.go new file mode 100644 index 00000000..34d64bc3 --- /dev/null +++ b/internal/server/iscsi/internal/v1alpha1/conversion_generated.go @@ -0,0 +1,425 @@ +// Code generated by csi-proxy-api-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + unsafe "unsafe" + + v1alpha1 "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1" + internal "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal" +) + +func autoConvert_v1alpha1_AddTargetPortalRequest_To_internal_AddTargetPortalRequest(in *v1alpha1.AddTargetPortalRequest, out *internal.AddTargetPortalRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(internal.TargetPortal) + if err := Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + return nil +} + +// Convert_v1alpha1_AddTargetPortalRequest_To_internal_AddTargetPortalRequest is an autogenerated conversion function. +func Convert_v1alpha1_AddTargetPortalRequest_To_internal_AddTargetPortalRequest(in *v1alpha1.AddTargetPortalRequest, out *internal.AddTargetPortalRequest) error { + return autoConvert_v1alpha1_AddTargetPortalRequest_To_internal_AddTargetPortalRequest(in, out) +} + +func autoConvert_internal_AddTargetPortalRequest_To_v1alpha1_AddTargetPortalRequest(in *internal.AddTargetPortalRequest, out *v1alpha1.AddTargetPortalRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(v1alpha1.TargetPortal) + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + return nil +} + +// Convert_internal_AddTargetPortalRequest_To_v1alpha1_AddTargetPortalRequest is an autogenerated conversion function. +func Convert_internal_AddTargetPortalRequest_To_v1alpha1_AddTargetPortalRequest(in *internal.AddTargetPortalRequest, out *v1alpha1.AddTargetPortalRequest) error { + return autoConvert_internal_AddTargetPortalRequest_To_v1alpha1_AddTargetPortalRequest(in, out) +} + +func autoConvert_v1alpha1_AddTargetPortalResponse_To_internal_AddTargetPortalResponse(in *v1alpha1.AddTargetPortalResponse, out *internal.AddTargetPortalResponse) error { + return nil +} + +// Convert_v1alpha1_AddTargetPortalResponse_To_internal_AddTargetPortalResponse is an autogenerated conversion function. +func Convert_v1alpha1_AddTargetPortalResponse_To_internal_AddTargetPortalResponse(in *v1alpha1.AddTargetPortalResponse, out *internal.AddTargetPortalResponse) error { + return autoConvert_v1alpha1_AddTargetPortalResponse_To_internal_AddTargetPortalResponse(in, out) +} + +func autoConvert_internal_AddTargetPortalResponse_To_v1alpha1_AddTargetPortalResponse(in *internal.AddTargetPortalResponse, out *v1alpha1.AddTargetPortalResponse) error { + return nil +} + +// Convert_internal_AddTargetPortalResponse_To_v1alpha1_AddTargetPortalResponse is an autogenerated conversion function. +func Convert_internal_AddTargetPortalResponse_To_v1alpha1_AddTargetPortalResponse(in *internal.AddTargetPortalResponse, out *v1alpha1.AddTargetPortalResponse) error { + return autoConvert_internal_AddTargetPortalResponse_To_v1alpha1_AddTargetPortalResponse(in, out) +} + +func autoConvert_v1alpha1_ConnectTargetRequest_To_internal_ConnectTargetRequest(in *v1alpha1.ConnectTargetRequest, out *internal.ConnectTargetRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(internal.TargetPortal) + if err := Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + out.Iqn = in.Iqn + out.AuthType = internal.AuthenticationType(in.AuthType) + out.ChapUsername = in.ChapUsername + out.ChapSecret = in.ChapSecret + return nil +} + +// Convert_v1alpha1_ConnectTargetRequest_To_internal_ConnectTargetRequest is an autogenerated conversion function. +func Convert_v1alpha1_ConnectTargetRequest_To_internal_ConnectTargetRequest(in *v1alpha1.ConnectTargetRequest, out *internal.ConnectTargetRequest) error { + return autoConvert_v1alpha1_ConnectTargetRequest_To_internal_ConnectTargetRequest(in, out) +} + +func autoConvert_internal_ConnectTargetRequest_To_v1alpha1_ConnectTargetRequest(in *internal.ConnectTargetRequest, out *v1alpha1.ConnectTargetRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(v1alpha1.TargetPortal) + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + out.Iqn = in.Iqn + out.AuthType = v1alpha1.AuthenticationType(in.AuthType) + out.ChapUsername = in.ChapUsername + out.ChapSecret = in.ChapSecret + return nil +} + +// Convert_internal_ConnectTargetRequest_To_v1alpha1_ConnectTargetRequest is an autogenerated conversion function. +func Convert_internal_ConnectTargetRequest_To_v1alpha1_ConnectTargetRequest(in *internal.ConnectTargetRequest, out *v1alpha1.ConnectTargetRequest) error { + return autoConvert_internal_ConnectTargetRequest_To_v1alpha1_ConnectTargetRequest(in, out) +} + +func autoConvert_v1alpha1_ConnectTargetResponse_To_internal_ConnectTargetResponse(in *v1alpha1.ConnectTargetResponse, out *internal.ConnectTargetResponse) error { + return nil +} + +// Convert_v1alpha1_ConnectTargetResponse_To_internal_ConnectTargetResponse is an autogenerated conversion function. +func Convert_v1alpha1_ConnectTargetResponse_To_internal_ConnectTargetResponse(in *v1alpha1.ConnectTargetResponse, out *internal.ConnectTargetResponse) error { + return autoConvert_v1alpha1_ConnectTargetResponse_To_internal_ConnectTargetResponse(in, out) +} + +func autoConvert_internal_ConnectTargetResponse_To_v1alpha1_ConnectTargetResponse(in *internal.ConnectTargetResponse, out *v1alpha1.ConnectTargetResponse) error { + return nil +} + +// Convert_internal_ConnectTargetResponse_To_v1alpha1_ConnectTargetResponse is an autogenerated conversion function. +func Convert_internal_ConnectTargetResponse_To_v1alpha1_ConnectTargetResponse(in *internal.ConnectTargetResponse, out *v1alpha1.ConnectTargetResponse) error { + return autoConvert_internal_ConnectTargetResponse_To_v1alpha1_ConnectTargetResponse(in, out) +} + +func autoConvert_v1alpha1_DisconnectTargetRequest_To_internal_DisconnectTargetRequest(in *v1alpha1.DisconnectTargetRequest, out *internal.DisconnectTargetRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(internal.TargetPortal) + if err := Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + out.Iqn = in.Iqn + return nil +} + +// Convert_v1alpha1_DisconnectTargetRequest_To_internal_DisconnectTargetRequest is an autogenerated conversion function. +func Convert_v1alpha1_DisconnectTargetRequest_To_internal_DisconnectTargetRequest(in *v1alpha1.DisconnectTargetRequest, out *internal.DisconnectTargetRequest) error { + return autoConvert_v1alpha1_DisconnectTargetRequest_To_internal_DisconnectTargetRequest(in, out) +} + +func autoConvert_internal_DisconnectTargetRequest_To_v1alpha1_DisconnectTargetRequest(in *internal.DisconnectTargetRequest, out *v1alpha1.DisconnectTargetRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(v1alpha1.TargetPortal) + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + out.Iqn = in.Iqn + return nil +} + +// Convert_internal_DisconnectTargetRequest_To_v1alpha1_DisconnectTargetRequest is an autogenerated conversion function. +func Convert_internal_DisconnectTargetRequest_To_v1alpha1_DisconnectTargetRequest(in *internal.DisconnectTargetRequest, out *v1alpha1.DisconnectTargetRequest) error { + return autoConvert_internal_DisconnectTargetRequest_To_v1alpha1_DisconnectTargetRequest(in, out) +} + +func autoConvert_v1alpha1_DisconnectTargetResponse_To_internal_DisconnectTargetResponse(in *v1alpha1.DisconnectTargetResponse, out *internal.DisconnectTargetResponse) error { + return nil +} + +// Convert_v1alpha1_DisconnectTargetResponse_To_internal_DisconnectTargetResponse is an autogenerated conversion function. +func Convert_v1alpha1_DisconnectTargetResponse_To_internal_DisconnectTargetResponse(in *v1alpha1.DisconnectTargetResponse, out *internal.DisconnectTargetResponse) error { + return autoConvert_v1alpha1_DisconnectTargetResponse_To_internal_DisconnectTargetResponse(in, out) +} + +func autoConvert_internal_DisconnectTargetResponse_To_v1alpha1_DisconnectTargetResponse(in *internal.DisconnectTargetResponse, out *v1alpha1.DisconnectTargetResponse) error { + return nil +} + +// Convert_internal_DisconnectTargetResponse_To_v1alpha1_DisconnectTargetResponse is an autogenerated conversion function. +func Convert_internal_DisconnectTargetResponse_To_v1alpha1_DisconnectTargetResponse(in *internal.DisconnectTargetResponse, out *v1alpha1.DisconnectTargetResponse) error { + return autoConvert_internal_DisconnectTargetResponse_To_v1alpha1_DisconnectTargetResponse(in, out) +} + +func autoConvert_v1alpha1_DiscoverTargetPortalRequest_To_internal_DiscoverTargetPortalRequest(in *v1alpha1.DiscoverTargetPortalRequest, out *internal.DiscoverTargetPortalRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(internal.TargetPortal) + if err := Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + return nil +} + +// Convert_v1alpha1_DiscoverTargetPortalRequest_To_internal_DiscoverTargetPortalRequest is an autogenerated conversion function. +func Convert_v1alpha1_DiscoverTargetPortalRequest_To_internal_DiscoverTargetPortalRequest(in *v1alpha1.DiscoverTargetPortalRequest, out *internal.DiscoverTargetPortalRequest) error { + return autoConvert_v1alpha1_DiscoverTargetPortalRequest_To_internal_DiscoverTargetPortalRequest(in, out) +} + +func autoConvert_internal_DiscoverTargetPortalRequest_To_v1alpha1_DiscoverTargetPortalRequest(in *internal.DiscoverTargetPortalRequest, out *v1alpha1.DiscoverTargetPortalRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(v1alpha1.TargetPortal) + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + return nil +} + +// Convert_internal_DiscoverTargetPortalRequest_To_v1alpha1_DiscoverTargetPortalRequest is an autogenerated conversion function. +func Convert_internal_DiscoverTargetPortalRequest_To_v1alpha1_DiscoverTargetPortalRequest(in *internal.DiscoverTargetPortalRequest, out *v1alpha1.DiscoverTargetPortalRequest) error { + return autoConvert_internal_DiscoverTargetPortalRequest_To_v1alpha1_DiscoverTargetPortalRequest(in, out) +} + +func autoConvert_v1alpha1_DiscoverTargetPortalResponse_To_internal_DiscoverTargetPortalResponse(in *v1alpha1.DiscoverTargetPortalResponse, out *internal.DiscoverTargetPortalResponse) error { + out.Iqns = *(*[]string)(unsafe.Pointer(&in.Iqns)) + return nil +} + +// Convert_v1alpha1_DiscoverTargetPortalResponse_To_internal_DiscoverTargetPortalResponse is an autogenerated conversion function. +func Convert_v1alpha1_DiscoverTargetPortalResponse_To_internal_DiscoverTargetPortalResponse(in *v1alpha1.DiscoverTargetPortalResponse, out *internal.DiscoverTargetPortalResponse) error { + return autoConvert_v1alpha1_DiscoverTargetPortalResponse_To_internal_DiscoverTargetPortalResponse(in, out) +} + +func autoConvert_internal_DiscoverTargetPortalResponse_To_v1alpha1_DiscoverTargetPortalResponse(in *internal.DiscoverTargetPortalResponse, out *v1alpha1.DiscoverTargetPortalResponse) error { + out.Iqns = *(*[]string)(unsafe.Pointer(&in.Iqns)) + return nil +} + +// Convert_internal_DiscoverTargetPortalResponse_To_v1alpha1_DiscoverTargetPortalResponse is an autogenerated conversion function. +func Convert_internal_DiscoverTargetPortalResponse_To_v1alpha1_DiscoverTargetPortalResponse(in *internal.DiscoverTargetPortalResponse, out *v1alpha1.DiscoverTargetPortalResponse) error { + return autoConvert_internal_DiscoverTargetPortalResponse_To_v1alpha1_DiscoverTargetPortalResponse(in, out) +} + +func autoConvert_v1alpha1_GetTargetDisksRequest_To_internal_GetTargetDisksRequest(in *v1alpha1.GetTargetDisksRequest, out *internal.GetTargetDisksRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(internal.TargetPortal) + if err := Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + out.Iqn = in.Iqn + return nil +} + +// Convert_v1alpha1_GetTargetDisksRequest_To_internal_GetTargetDisksRequest is an autogenerated conversion function. +func Convert_v1alpha1_GetTargetDisksRequest_To_internal_GetTargetDisksRequest(in *v1alpha1.GetTargetDisksRequest, out *internal.GetTargetDisksRequest) error { + return autoConvert_v1alpha1_GetTargetDisksRequest_To_internal_GetTargetDisksRequest(in, out) +} + +func autoConvert_internal_GetTargetDisksRequest_To_v1alpha1_GetTargetDisksRequest(in *internal.GetTargetDisksRequest, out *v1alpha1.GetTargetDisksRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(v1alpha1.TargetPortal) + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + out.Iqn = in.Iqn + return nil +} + +// Convert_internal_GetTargetDisksRequest_To_v1alpha1_GetTargetDisksRequest is an autogenerated conversion function. +func Convert_internal_GetTargetDisksRequest_To_v1alpha1_GetTargetDisksRequest(in *internal.GetTargetDisksRequest, out *v1alpha1.GetTargetDisksRequest) error { + return autoConvert_internal_GetTargetDisksRequest_To_v1alpha1_GetTargetDisksRequest(in, out) +} + +func autoConvert_v1alpha1_GetTargetDisksResponse_To_internal_GetTargetDisksResponse(in *v1alpha1.GetTargetDisksResponse, out *internal.GetTargetDisksResponse) error { + out.DiskIDs = *(*[]string)(unsafe.Pointer(&in.DiskIDs)) + return nil +} + +// Convert_v1alpha1_GetTargetDisksResponse_To_internal_GetTargetDisksResponse is an autogenerated conversion function. +func Convert_v1alpha1_GetTargetDisksResponse_To_internal_GetTargetDisksResponse(in *v1alpha1.GetTargetDisksResponse, out *internal.GetTargetDisksResponse) error { + return autoConvert_v1alpha1_GetTargetDisksResponse_To_internal_GetTargetDisksResponse(in, out) +} + +func autoConvert_internal_GetTargetDisksResponse_To_v1alpha1_GetTargetDisksResponse(in *internal.GetTargetDisksResponse, out *v1alpha1.GetTargetDisksResponse) error { + out.DiskIDs = *(*[]string)(unsafe.Pointer(&in.DiskIDs)) + return nil +} + +// Convert_internal_GetTargetDisksResponse_To_v1alpha1_GetTargetDisksResponse is an autogenerated conversion function. +func Convert_internal_GetTargetDisksResponse_To_v1alpha1_GetTargetDisksResponse(in *internal.GetTargetDisksResponse, out *v1alpha1.GetTargetDisksResponse) error { + return autoConvert_internal_GetTargetDisksResponse_To_v1alpha1_GetTargetDisksResponse(in, out) +} + +func autoConvert_v1alpha1_ListTargetPortalsRequest_To_internal_ListTargetPortalsRequest(in *v1alpha1.ListTargetPortalsRequest, out *internal.ListTargetPortalsRequest) error { + return nil +} + +// Convert_v1alpha1_ListTargetPortalsRequest_To_internal_ListTargetPortalsRequest is an autogenerated conversion function. +func Convert_v1alpha1_ListTargetPortalsRequest_To_internal_ListTargetPortalsRequest(in *v1alpha1.ListTargetPortalsRequest, out *internal.ListTargetPortalsRequest) error { + return autoConvert_v1alpha1_ListTargetPortalsRequest_To_internal_ListTargetPortalsRequest(in, out) +} + +func autoConvert_internal_ListTargetPortalsRequest_To_v1alpha1_ListTargetPortalsRequest(in *internal.ListTargetPortalsRequest, out *v1alpha1.ListTargetPortalsRequest) error { + return nil +} + +// Convert_internal_ListTargetPortalsRequest_To_v1alpha1_ListTargetPortalsRequest is an autogenerated conversion function. +func Convert_internal_ListTargetPortalsRequest_To_v1alpha1_ListTargetPortalsRequest(in *internal.ListTargetPortalsRequest, out *v1alpha1.ListTargetPortalsRequest) error { + return autoConvert_internal_ListTargetPortalsRequest_To_v1alpha1_ListTargetPortalsRequest(in, out) +} + +func autoConvert_v1alpha1_ListTargetPortalsResponse_To_internal_ListTargetPortalsResponse(in *v1alpha1.ListTargetPortalsResponse, out *internal.ListTargetPortalsResponse) error { + if in.TargetPortals != nil { + in, out := &in.TargetPortals, &out.TargetPortals + *out = make([]*internal.TargetPortal, len(*in)) + for i := range *in { + if err := Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(*&(*in)[i], *&(*out)[i]); err != nil { + return err + } + } + } else { + out.TargetPortals = nil + } + return nil +} + +// Convert_v1alpha1_ListTargetPortalsResponse_To_internal_ListTargetPortalsResponse is an autogenerated conversion function. +func Convert_v1alpha1_ListTargetPortalsResponse_To_internal_ListTargetPortalsResponse(in *v1alpha1.ListTargetPortalsResponse, out *internal.ListTargetPortalsResponse) error { + return autoConvert_v1alpha1_ListTargetPortalsResponse_To_internal_ListTargetPortalsResponse(in, out) +} + +func autoConvert_internal_ListTargetPortalsResponse_To_v1alpha1_ListTargetPortalsResponse(in *internal.ListTargetPortalsResponse, out *v1alpha1.ListTargetPortalsResponse) error { + if in.TargetPortals != nil { + in, out := &in.TargetPortals, &out.TargetPortals + *out = make([]*v1alpha1.TargetPortal, len(*in)) + for i := range *in { + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*&(*in)[i], *&(*out)[i]); err != nil { + return err + } + } + } else { + out.TargetPortals = nil + } + return nil +} + +func autoConvert_v1alpha1_RemoveTargetPortalRequest_To_internal_RemoveTargetPortalRequest(in *v1alpha1.RemoveTargetPortalRequest, out *internal.RemoveTargetPortalRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(internal.TargetPortal) + if err := Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + return nil +} + +// Convert_v1alpha1_RemoveTargetPortalRequest_To_internal_RemoveTargetPortalRequest is an autogenerated conversion function. +func Convert_v1alpha1_RemoveTargetPortalRequest_To_internal_RemoveTargetPortalRequest(in *v1alpha1.RemoveTargetPortalRequest, out *internal.RemoveTargetPortalRequest) error { + return autoConvert_v1alpha1_RemoveTargetPortalRequest_To_internal_RemoveTargetPortalRequest(in, out) +} + +func autoConvert_internal_RemoveTargetPortalRequest_To_v1alpha1_RemoveTargetPortalRequest(in *internal.RemoveTargetPortalRequest, out *v1alpha1.RemoveTargetPortalRequest) error { + if in.TargetPortal != nil { + in, out := &in.TargetPortal, &out.TargetPortal + *out = new(v1alpha1.TargetPortal) + if err := Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(*in, *out); err != nil { + return err + } + } else { + out.TargetPortal = nil + } + return nil +} + +// Convert_internal_RemoveTargetPortalRequest_To_v1alpha1_RemoveTargetPortalRequest is an autogenerated conversion function. +func Convert_internal_RemoveTargetPortalRequest_To_v1alpha1_RemoveTargetPortalRequest(in *internal.RemoveTargetPortalRequest, out *v1alpha1.RemoveTargetPortalRequest) error { + return autoConvert_internal_RemoveTargetPortalRequest_To_v1alpha1_RemoveTargetPortalRequest(in, out) +} + +func autoConvert_v1alpha1_RemoveTargetPortalResponse_To_internal_RemoveTargetPortalResponse(in *v1alpha1.RemoveTargetPortalResponse, out *internal.RemoveTargetPortalResponse) error { + return nil +} + +// Convert_v1alpha1_RemoveTargetPortalResponse_To_internal_RemoveTargetPortalResponse is an autogenerated conversion function. +func Convert_v1alpha1_RemoveTargetPortalResponse_To_internal_RemoveTargetPortalResponse(in *v1alpha1.RemoveTargetPortalResponse, out *internal.RemoveTargetPortalResponse) error { + return autoConvert_v1alpha1_RemoveTargetPortalResponse_To_internal_RemoveTargetPortalResponse(in, out) +} + +func autoConvert_internal_RemoveTargetPortalResponse_To_v1alpha1_RemoveTargetPortalResponse(in *internal.RemoveTargetPortalResponse, out *v1alpha1.RemoveTargetPortalResponse) error { + return nil +} + +// Convert_internal_RemoveTargetPortalResponse_To_v1alpha1_RemoveTargetPortalResponse is an autogenerated conversion function. +func Convert_internal_RemoveTargetPortalResponse_To_v1alpha1_RemoveTargetPortalResponse(in *internal.RemoveTargetPortalResponse, out *v1alpha1.RemoveTargetPortalResponse) error { + return autoConvert_internal_RemoveTargetPortalResponse_To_v1alpha1_RemoveTargetPortalResponse(in, out) +} + +func autoConvert_v1alpha1_TargetPortal_To_internal_TargetPortal(in *v1alpha1.TargetPortal, out *internal.TargetPortal) error { + out.TargetAddress = in.TargetAddress + out.TargetPort = in.TargetPort + return nil +} + +// Convert_v1alpha1_TargetPortal_To_internal_TargetPortal is an autogenerated conversion function. +func Convert_v1alpha1_TargetPortal_To_internal_TargetPortal(in *v1alpha1.TargetPortal, out *internal.TargetPortal) error { + return autoConvert_v1alpha1_TargetPortal_To_internal_TargetPortal(in, out) +} + +func autoConvert_internal_TargetPortal_To_v1alpha1_TargetPortal(in *internal.TargetPortal, out *v1alpha1.TargetPortal) error { + out.TargetAddress = in.TargetAddress + out.TargetPort = in.TargetPort + return nil +} + +// Convert_internal_TargetPortal_To_v1alpha1_TargetPortal is an autogenerated conversion function. +func Convert_internal_TargetPortal_To_v1alpha1_TargetPortal(in *internal.TargetPortal, out *v1alpha1.TargetPortal) error { + return autoConvert_internal_TargetPortal_To_v1alpha1_TargetPortal(in, out) +} diff --git a/internal/server/iscsi/internal/v1alpha1/server_generated.go b/internal/server/iscsi/internal/v1alpha1/server_generated.go new file mode 100644 index 00000000..fe0cbaef --- /dev/null +++ b/internal/server/iscsi/internal/v1alpha1/server_generated.go @@ -0,0 +1,161 @@ +// Code generated by csi-proxy-api-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + + "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1" + "github.com/kubernetes-csi/csi-proxy/client/apiversion" + "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal" + "google.golang.org/grpc" +) + +var version = apiversion.NewVersionOrPanic("v1alpha1") + +type versionedAPI struct { + apiGroupServer internal.ServerInterface +} + +func NewVersionedServer(apiGroupServer internal.ServerInterface) internal.VersionedAPI { + return &versionedAPI{ + apiGroupServer: apiGroupServer, + } +} + +func (s *versionedAPI) Register(grpcServer *grpc.Server) { + v1alpha1.RegisterIscsiServer(grpcServer, s) +} + +func (s *versionedAPI) AddTargetPortal(context context.Context, versionedRequest *v1alpha1.AddTargetPortalRequest) (*v1alpha1.AddTargetPortalResponse, error) { + request := &internal.AddTargetPortalRequest{} + if err := Convert_v1alpha1_AddTargetPortalRequest_To_internal_AddTargetPortalRequest(versionedRequest, request); err != nil { + return nil, err + } + + response, err := s.apiGroupServer.AddTargetPortal(context, request, version) + if err != nil { + return nil, err + } + + versionedResponse := &v1alpha1.AddTargetPortalResponse{} + if err := Convert_internal_AddTargetPortalResponse_To_v1alpha1_AddTargetPortalResponse(response, versionedResponse); err != nil { + return nil, err + } + + return versionedResponse, err +} + +func (s *versionedAPI) ConnectTarget(context context.Context, versionedRequest *v1alpha1.ConnectTargetRequest) (*v1alpha1.ConnectTargetResponse, error) { + request := &internal.ConnectTargetRequest{} + if err := Convert_v1alpha1_ConnectTargetRequest_To_internal_ConnectTargetRequest(versionedRequest, request); err != nil { + return nil, err + } + + response, err := s.apiGroupServer.ConnectTarget(context, request, version) + if err != nil { + return nil, err + } + + versionedResponse := &v1alpha1.ConnectTargetResponse{} + if err := Convert_internal_ConnectTargetResponse_To_v1alpha1_ConnectTargetResponse(response, versionedResponse); err != nil { + return nil, err + } + + return versionedResponse, err +} + +func (s *versionedAPI) DisconnectTarget(context context.Context, versionedRequest *v1alpha1.DisconnectTargetRequest) (*v1alpha1.DisconnectTargetResponse, error) { + request := &internal.DisconnectTargetRequest{} + if err := Convert_v1alpha1_DisconnectTargetRequest_To_internal_DisconnectTargetRequest(versionedRequest, request); err != nil { + return nil, err + } + + response, err := s.apiGroupServer.DisconnectTarget(context, request, version) + if err != nil { + return nil, err + } + + versionedResponse := &v1alpha1.DisconnectTargetResponse{} + if err := Convert_internal_DisconnectTargetResponse_To_v1alpha1_DisconnectTargetResponse(response, versionedResponse); err != nil { + return nil, err + } + + return versionedResponse, err +} + +func (s *versionedAPI) DiscoverTargetPortal(context context.Context, versionedRequest *v1alpha1.DiscoverTargetPortalRequest) (*v1alpha1.DiscoverTargetPortalResponse, error) { + request := &internal.DiscoverTargetPortalRequest{} + if err := Convert_v1alpha1_DiscoverTargetPortalRequest_To_internal_DiscoverTargetPortalRequest(versionedRequest, request); err != nil { + return nil, err + } + + response, err := s.apiGroupServer.DiscoverTargetPortal(context, request, version) + if err != nil { + return nil, err + } + + versionedResponse := &v1alpha1.DiscoverTargetPortalResponse{} + if err := Convert_internal_DiscoverTargetPortalResponse_To_v1alpha1_DiscoverTargetPortalResponse(response, versionedResponse); err != nil { + return nil, err + } + + return versionedResponse, err +} + +func (s *versionedAPI) GetTargetDisks(context context.Context, versionedRequest *v1alpha1.GetTargetDisksRequest) (*v1alpha1.GetTargetDisksResponse, error) { + request := &internal.GetTargetDisksRequest{} + if err := Convert_v1alpha1_GetTargetDisksRequest_To_internal_GetTargetDisksRequest(versionedRequest, request); err != nil { + return nil, err + } + + response, err := s.apiGroupServer.GetTargetDisks(context, request, version) + if err != nil { + return nil, err + } + + versionedResponse := &v1alpha1.GetTargetDisksResponse{} + if err := Convert_internal_GetTargetDisksResponse_To_v1alpha1_GetTargetDisksResponse(response, versionedResponse); err != nil { + return nil, err + } + + return versionedResponse, err +} + +func (s *versionedAPI) ListTargetPortals(context context.Context, versionedRequest *v1alpha1.ListTargetPortalsRequest) (*v1alpha1.ListTargetPortalsResponse, error) { + request := &internal.ListTargetPortalsRequest{} + if err := Convert_v1alpha1_ListTargetPortalsRequest_To_internal_ListTargetPortalsRequest(versionedRequest, request); err != nil { + return nil, err + } + + response, err := s.apiGroupServer.ListTargetPortals(context, request, version) + if err != nil { + return nil, err + } + + versionedResponse := &v1alpha1.ListTargetPortalsResponse{} + if err := Convert_internal_ListTargetPortalsResponse_To_v1alpha1_ListTargetPortalsResponse(response, versionedResponse); err != nil { + return nil, err + } + + return versionedResponse, err +} + +func (s *versionedAPI) RemoveTargetPortal(context context.Context, versionedRequest *v1alpha1.RemoveTargetPortalRequest) (*v1alpha1.RemoveTargetPortalResponse, error) { + request := &internal.RemoveTargetPortalRequest{} + if err := Convert_v1alpha1_RemoveTargetPortalRequest_To_internal_RemoveTargetPortalRequest(versionedRequest, request); err != nil { + return nil, err + } + + response, err := s.apiGroupServer.RemoveTargetPortal(context, request, version) + if err != nil { + return nil, err + } + + versionedResponse := &v1alpha1.RemoveTargetPortalResponse{} + if err := Convert_internal_RemoveTargetPortalResponse_To_v1alpha1_RemoveTargetPortalResponse(response, versionedResponse); err != nil { + return nil, err + } + + return versionedResponse, err +} diff --git a/internal/server/iscsi/server.go b/internal/server/iscsi/server.go new file mode 100644 index 00000000..d1daac74 --- /dev/null +++ b/internal/server/iscsi/server.go @@ -0,0 +1,170 @@ +package iscsi + +import ( + "context" + "fmt" + + "github.com/kubernetes-csi/csi-proxy/client/apiversion" + "github.com/kubernetes-csi/csi-proxy/internal/os/iscsi" + "github.com/kubernetes-csi/csi-proxy/internal/server/iscsi/internal" + "k8s.io/klog" +) + +const defaultIscsiPort = 3260 + +type Server struct { + hostAPI API +} + +type API interface { + AddTargetPortal(portal *iscsi.TargetPortal) error + DiscoverTargetPortal(portal *iscsi.TargetPortal) ([]string, error) + ListTargetPortals() ([]iscsi.TargetPortal, error) + RemoveTargetPortal(portal *iscsi.TargetPortal) error + ConnectTarget(portal *iscsi.TargetPortal, iqn string, authType string, + chapUser string, chapSecret string) error + DisconnectTarget(portal *iscsi.TargetPortal, iqn string) error + GetTargetDisks(portal *iscsi.TargetPortal, iqn string) ([]string, error) +} + +func NewServer(hostAPI API) (*Server, error) { + return &Server{ + hostAPI: hostAPI, + }, nil +} + +func (s *Server) requestTPtoAPITP(portal *internal.TargetPortal) *iscsi.TargetPortal { + port := portal.TargetPort + if port == 0 { + port = defaultIscsiPort + } + return &iscsi.TargetPortal{Address: portal.TargetAddress, Port: port} +} + +func (s *Server) AddTargetPortal(context context.Context, request *internal.AddTargetPortalRequest, version apiversion.Version) (*internal.AddTargetPortalResponse, error) { + klog.V(4).Infof("calling AddTargetPortal with portal %s:%d", request.TargetPortal.TargetAddress, request.TargetPortal.TargetPort) + response := &internal.AddTargetPortalResponse{} + err := s.hostAPI.AddTargetPortal(s.requestTPtoAPITP(request.TargetPortal)) + if err != nil { + klog.Errorf("failed AddTargetPortal %v", err) + return response, err + } + + return response, nil +} + +func AuthTypeToString(authType internal.AuthenticationType) (string, error) { + switch authType { + case internal.NONE: + return "NONE", nil + case internal.ONE_WAY_CHAP: + return "ONEWAYCHAP", nil + case internal.MUTUAL_CHAP: + return "MUTUALCHAP", nil + default: + return "", fmt.Errorf("invalid authentication type authType=%v", authType) + } +} + +func (s *Server) ConnectTarget(context context.Context, req *internal.ConnectTargetRequest, version apiversion.Version) (*internal.ConnectTargetResponse, error) { + klog.V(4).Infof("calling ConnectTarget with portal %s:%d and iqn %s"+ + " auth=%v chapuser=%v", req.TargetPortal.TargetAddress, + req.TargetPortal.TargetPort, req.Iqn, req.AuthType, req.ChapUsername) + + response := &internal.ConnectTargetResponse{} + authType, err := AuthTypeToString(req.AuthType) + if err != nil { + klog.Errorf("Error parsing parameters: %v", err) + return response, err + } + + err = s.hostAPI.ConnectTarget(s.requestTPtoAPITP(req.TargetPortal), req.Iqn, + authType, req.ChapUsername, req.ChapSecret) + if err != nil { + klog.Errorf("failed ConnectTarget %v", err) + return response, err + } + + return response, nil +} + +func (s *Server) DisconnectTarget(context context.Context, request *internal.DisconnectTargetRequest, version apiversion.Version) (*internal.DisconnectTargetResponse, error) { + klog.V(4).Infof("calling DisconnectTarget with portal %s:%d and iqn %s", + request.TargetPortal.TargetAddress, request.TargetPortal.TargetPort, request.Iqn) + + response := &internal.DisconnectTargetResponse{} + err := s.hostAPI.DisconnectTarget(s.requestTPtoAPITP(request.TargetPortal), request.Iqn) + if err != nil { + klog.Errorf("failed DisconnectTarget %v", err) + return response, err + } + + return response, nil +} + +func (s *Server) DiscoverTargetPortal(context context.Context, request *internal.DiscoverTargetPortalRequest, version apiversion.Version) (*internal.DiscoverTargetPortalResponse, error) { + klog.V(4).Infof("calling DiscoverTargetPortal with portal %s:%d", request.TargetPortal.TargetAddress, request.TargetPortal.TargetPort) + response := &internal.DiscoverTargetPortalResponse{} + iqns, err := s.hostAPI.DiscoverTargetPortal(s.requestTPtoAPITP(request.TargetPortal)) + if err != nil { + klog.Errorf("failed DiscoverTargetPortal %v", err) + return response, err + } + + response.Iqns = iqns + return response, nil +} + +func (s *Server) GetTargetDisks(context context.Context, request *internal.GetTargetDisksRequest, version apiversion.Version) (*internal.GetTargetDisksResponse, error) { + klog.V(4).Infof("calling GetTargetDisks with portal %s:%d and iqn %s", + request.TargetPortal.TargetAddress, request.TargetPortal.TargetPort, request.Iqn) + response := &internal.GetTargetDisksResponse{} + disks, err := s.hostAPI.GetTargetDisks(s.requestTPtoAPITP(request.TargetPortal), request.Iqn) + if err != nil { + klog.Errorf("failed GetTargetDisks %v", err) + return response, err + } + + result := make([]string, 0, len(disks)) + for _, d := range disks { + result = append(result, d) + } + + response.DiskIDs = result + + return response, nil +} + +func (s *Server) ListTargetPortals(context context.Context, request *internal.ListTargetPortalsRequest, version apiversion.Version) (*internal.ListTargetPortalsResponse, error) { + klog.V(4).Infof("calling ListTargetPortals") + response := &internal.ListTargetPortalsResponse{} + portals, err := s.hostAPI.ListTargetPortals() + if err != nil { + klog.Errorf("failed ListTargetPortals %v", err) + return response, err + } + + result := make([]*internal.TargetPortal, 0, len(portals)) + for _, p := range portals { + result = append(result, &internal.TargetPortal{ + TargetAddress: p.Address, + TargetPort: p.Port, + }) + } + + response.TargetPortals = result + + return response, nil +} + +func (s *Server) RemoveTargetPortal(context context.Context, request *internal.RemoveTargetPortalRequest, version apiversion.Version) (*internal.RemoveTargetPortalResponse, error) { + klog.V(4).Infof("calling RemoveTargetPortal with portal %s:%d", request.TargetPortal.TargetAddress, request.TargetPortal.TargetPort) + response := &internal.RemoveTargetPortalResponse{} + err := s.hostAPI.RemoveTargetPortal(s.requestTPtoAPITP(request.TargetPortal)) + if err != nil { + klog.Errorf("failed RemoveTargetPortal %v", err) + return response, err + } + + return response, nil +} diff --git a/vendor/github.com/google/go-cmp/LICENSE b/vendor/github.com/google/go-cmp/LICENSE new file mode 100644 index 00000000..32017f8f --- /dev/null +++ b/vendor/github.com/google/go-cmp/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2017 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go new file mode 100644 index 00000000..8667908c --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go @@ -0,0 +1,156 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// Package cmpopts provides common options for the cmp package. +package cmpopts + +import ( + "math" + "reflect" + "time" + + "github.com/google/go-cmp/cmp" + "golang.org/x/xerrors" +) + +func equateAlways(_, _ interface{}) bool { return true } + +// EquateEmpty returns a Comparer option that determines all maps and slices +// with a length of zero to be equal, regardless of whether they are nil. +// +// EquateEmpty can be used in conjunction with SortSlices and SortMaps. +func EquateEmpty() cmp.Option { + return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways)) +} + +func isEmpty(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + return (x != nil && y != nil && vx.Type() == vy.Type()) && + (vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) && + (vx.Len() == 0 && vy.Len() == 0) +} + +// EquateApprox returns a Comparer option that determines float32 or float64 +// values to be equal if they are within a relative fraction or absolute margin. +// This option is not used when either x or y is NaN or infinite. +// +// The fraction determines that the difference of two values must be within the +// smaller fraction of the two values, while the margin determines that the two +// values must be within some absolute margin. +// To express only a fraction or only a margin, use 0 for the other parameter. +// The fraction and margin must be non-negative. +// +// The mathematical expression used is equivalent to: +// |x-y| ≤ max(fraction*min(|x|, |y|), margin) +// +// EquateApprox can be used in conjunction with EquateNaNs. +func EquateApprox(fraction, margin float64) cmp.Option { + if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) { + panic("margin or fraction must be a non-negative number") + } + a := approximator{fraction, margin} + return cmp.Options{ + cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)), + cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)), + } +} + +type approximator struct{ frac, marg float64 } + +func areRealF64s(x, y float64) bool { + return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0) +} +func areRealF32s(x, y float32) bool { + return areRealF64s(float64(x), float64(y)) +} +func (a approximator) compareF64(x, y float64) bool { + relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y)) + return math.Abs(x-y) <= math.Max(a.marg, relMarg) +} +func (a approximator) compareF32(x, y float32) bool { + return a.compareF64(float64(x), float64(y)) +} + +// EquateNaNs returns a Comparer option that determines float32 and float64 +// NaN values to be equal. +// +// EquateNaNs can be used in conjunction with EquateApprox. +func EquateNaNs() cmp.Option { + return cmp.Options{ + cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)), + cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)), + } +} + +func areNaNsF64s(x, y float64) bool { + return math.IsNaN(x) && math.IsNaN(y) +} +func areNaNsF32s(x, y float32) bool { + return areNaNsF64s(float64(x), float64(y)) +} + +// EquateApproxTime returns a Comparer option that determines two non-zero +// time.Time values to be equal if they are within some margin of one another. +// If both times have a monotonic clock reading, then the monotonic time +// difference will be used. The margin must be non-negative. +func EquateApproxTime(margin time.Duration) cmp.Option { + if margin < 0 { + panic("margin must be a non-negative number") + } + a := timeApproximator{margin} + return cmp.FilterValues(areNonZeroTimes, cmp.Comparer(a.compare)) +} + +func areNonZeroTimes(x, y time.Time) bool { + return !x.IsZero() && !y.IsZero() +} + +type timeApproximator struct { + margin time.Duration +} + +func (a timeApproximator) compare(x, y time.Time) bool { + // Avoid subtracting times to avoid overflow when the + // difference is larger than the largest representible duration. + if x.After(y) { + // Ensure x is always before y + x, y = y, x + } + // We're within the margin if x+margin >= y. + // Note: time.Time doesn't have AfterOrEqual method hence the negation. + return !x.Add(a.margin).Before(y) +} + +// AnyError is an error that matches any non-nil error. +var AnyError anyError + +type anyError struct{} + +func (anyError) Error() string { return "any error" } +func (anyError) Is(err error) bool { return err != nil } + +// EquateErrors returns a Comparer option that determines errors to be equal +// if errors.Is reports them to match. The AnyError error can be used to +// match any non-nil error. +func EquateErrors() cmp.Option { + return cmp.FilterValues(areConcreteErrors, cmp.Comparer(compareErrors)) +} + +// areConcreteErrors reports whether x and y are types that implement error. +// The input types are deliberately of the interface{} type rather than the +// error type so that we can handle situations where the current type is an +// interface{}, but the underlying concrete types both happen to implement +// the error interface. +func areConcreteErrors(x, y interface{}) bool { + _, ok1 := x.(error) + _, ok2 := y.(error) + return ok1 && ok2 +} + +func compareErrors(x, y interface{}) bool { + xe := x.(error) + ye := y.(error) + // TODO(≥go1.13): Use standard definition of errors.Is. + return xerrors.Is(xe, ye) || xerrors.Is(ye, xe) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go new file mode 100644 index 00000000..afd36bee --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go @@ -0,0 +1,206 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "fmt" + "reflect" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/internal/function" +) + +// IgnoreFields returns an Option that ignores fields of the +// given names on a single struct type. It respects the names of exported fields +// that are forwarded due to struct embedding. +// The struct type is specified by passing in a value of that type. +// +// The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a +// specific sub-field that is embedded or nested within the parent struct. +func IgnoreFields(typ interface{}, names ...string) cmp.Option { + sf := newStructFilter(typ, names...) + return cmp.FilterPath(sf.filter, cmp.Ignore()) +} + +// IgnoreTypes returns an Option that ignores all values assignable to +// certain types, which are specified by passing in a value of each type. +func IgnoreTypes(typs ...interface{}) cmp.Option { + tf := newTypeFilter(typs...) + return cmp.FilterPath(tf.filter, cmp.Ignore()) +} + +type typeFilter []reflect.Type + +func newTypeFilter(typs ...interface{}) (tf typeFilter) { + for _, typ := range typs { + t := reflect.TypeOf(typ) + if t == nil { + // This occurs if someone tries to pass in sync.Locker(nil) + panic("cannot determine type; consider using IgnoreInterfaces") + } + tf = append(tf, t) + } + return tf +} +func (tf typeFilter) filter(p cmp.Path) bool { + if len(p) < 1 { + return false + } + t := p.Last().Type() + for _, ti := range tf { + if t.AssignableTo(ti) { + return true + } + } + return false +} + +// IgnoreInterfaces returns an Option that ignores all values or references of +// values assignable to certain interface types. These interfaces are specified +// by passing in an anonymous struct with the interface types embedded in it. +// For example, to ignore sync.Locker, pass in struct{sync.Locker}{}. +func IgnoreInterfaces(ifaces interface{}) cmp.Option { + tf := newIfaceFilter(ifaces) + return cmp.FilterPath(tf.filter, cmp.Ignore()) +} + +type ifaceFilter []reflect.Type + +func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) { + t := reflect.TypeOf(ifaces) + if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct { + panic("input must be an anonymous struct") + } + for i := 0; i < t.NumField(); i++ { + fi := t.Field(i) + switch { + case !fi.Anonymous: + panic("struct cannot have named fields") + case fi.Type.Kind() != reflect.Interface: + panic("embedded field must be an interface type") + case fi.Type.NumMethod() == 0: + // This matches everything; why would you ever want this? + panic("cannot ignore empty interface") + default: + tf = append(tf, fi.Type) + } + } + return tf +} +func (tf ifaceFilter) filter(p cmp.Path) bool { + if len(p) < 1 { + return false + } + t := p.Last().Type() + for _, ti := range tf { + if t.AssignableTo(ti) { + return true + } + if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) { + return true + } + } + return false +} + +// IgnoreUnexported returns an Option that only ignores the immediate unexported +// fields of a struct, including anonymous fields of unexported types. +// In particular, unexported fields within the struct's exported fields +// of struct types, including anonymous fields, will not be ignored unless the +// type of the field itself is also passed to IgnoreUnexported. +// +// Avoid ignoring unexported fields of a type which you do not control (i.e. a +// type from another repository), as changes to the implementation of such types +// may change how the comparison behaves. Prefer a custom Comparer instead. +func IgnoreUnexported(typs ...interface{}) cmp.Option { + ux := newUnexportedFilter(typs...) + return cmp.FilterPath(ux.filter, cmp.Ignore()) +} + +type unexportedFilter struct{ m map[reflect.Type]bool } + +func newUnexportedFilter(typs ...interface{}) unexportedFilter { + ux := unexportedFilter{m: make(map[reflect.Type]bool)} + for _, typ := range typs { + t := reflect.TypeOf(typ) + if t == nil || t.Kind() != reflect.Struct { + panic(fmt.Sprintf("invalid struct type: %T", typ)) + } + ux.m[t] = true + } + return ux +} +func (xf unexportedFilter) filter(p cmp.Path) bool { + sf, ok := p.Index(-1).(cmp.StructField) + if !ok { + return false + } + return xf.m[p.Index(-2).Type()] && !isExported(sf.Name()) +} + +// isExported reports whether the identifier is exported. +func isExported(id string) bool { + r, _ := utf8.DecodeRuneInString(id) + return unicode.IsUpper(r) +} + +// IgnoreSliceElements returns an Option that ignores elements of []V. +// The discard function must be of the form "func(T) bool" which is used to +// ignore slice elements of type V, where V is assignable to T. +// Elements are ignored if the function reports true. +func IgnoreSliceElements(discardFunc interface{}) cmp.Option { + vf := reflect.ValueOf(discardFunc) + if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() { + panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) + } + return cmp.FilterPath(func(p cmp.Path) bool { + si, ok := p.Index(-1).(cmp.SliceIndex) + if !ok { + return false + } + if !si.Type().AssignableTo(vf.Type().In(0)) { + return false + } + vx, vy := si.Values() + if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() { + return true + } + if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() { + return true + } + return false + }, cmp.Ignore()) +} + +// IgnoreMapEntries returns an Option that ignores entries of map[K]V. +// The discard function must be of the form "func(T, R) bool" which is used to +// ignore map entries of type K and V, where K and V are assignable to T and R. +// Entries are ignored if the function reports true. +func IgnoreMapEntries(discardFunc interface{}) cmp.Option { + vf := reflect.ValueOf(discardFunc) + if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() { + panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) + } + return cmp.FilterPath(func(p cmp.Path) bool { + mi, ok := p.Index(-1).(cmp.MapIndex) + if !ok { + return false + } + if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) { + return false + } + k := mi.Key() + vx, vy := mi.Values() + if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() { + return true + } + if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() { + return true + } + return false + }, cmp.Ignore()) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go new file mode 100644 index 00000000..3a480462 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go @@ -0,0 +1,147 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "fmt" + "reflect" + "sort" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/internal/function" +) + +// SortSlices returns a Transformer option that sorts all []V. +// The less function must be of the form "func(T, T) bool" which is used to +// sort any slice with element type V that is assignable to T. +// +// The less function must be: +// • Deterministic: less(x, y) == less(x, y) +// • Irreflexive: !less(x, x) +// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// +// The less function does not have to be "total". That is, if !less(x, y) and +// !less(y, x) for two elements x and y, their relative order is maintained. +// +// SortSlices can be used in conjunction with EquateEmpty. +func SortSlices(lessFunc interface{}) cmp.Option { + vf := reflect.ValueOf(lessFunc) + if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { + panic(fmt.Sprintf("invalid less function: %T", lessFunc)) + } + ss := sliceSorter{vf.Type().In(0), vf} + return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort)) +} + +type sliceSorter struct { + in reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (ss sliceSorter) filter(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + if !(x != nil && y != nil && vx.Type() == vy.Type()) || + !(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) || + (vx.Len() <= 1 && vy.Len() <= 1) { + return false + } + // Check whether the slices are already sorted to avoid an infinite + // recursion cycle applying the same transform to itself. + ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) }) + ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) }) + return !ok1 || !ok2 +} +func (ss sliceSorter) sort(x interface{}) interface{} { + src := reflect.ValueOf(x) + dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len()) + for i := 0; i < src.Len(); i++ { + dst.Index(i).Set(src.Index(i)) + } + sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) }) + ss.checkSort(dst) + return dst.Interface() +} +func (ss sliceSorter) checkSort(v reflect.Value) { + start := -1 // Start of a sequence of equal elements. + for i := 1; i < v.Len(); i++ { + if ss.less(v, i-1, i) { + // Check that first and last elements in v[start:i] are equal. + if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) { + panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i))) + } + start = -1 + } else if start == -1 { + start = i + } + } +} +func (ss sliceSorter) less(v reflect.Value, i, j int) bool { + vx, vy := v.Index(i), v.Index(j) + return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool() +} + +// SortMaps returns a Transformer option that flattens map[K]V types to be a +// sorted []struct{K, V}. The less function must be of the form +// "func(T, T) bool" which is used to sort any map with key K that is +// assignable to T. +// +// Flattening the map into a slice has the property that cmp.Equal is able to +// use Comparers on K or the K.Equal method if it exists. +// +// The less function must be: +// • Deterministic: less(x, y) == less(x, y) +// • Irreflexive: !less(x, x) +// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// • Total: if x != y, then either less(x, y) or less(y, x) +// +// SortMaps can be used in conjunction with EquateEmpty. +func SortMaps(lessFunc interface{}) cmp.Option { + vf := reflect.ValueOf(lessFunc) + if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { + panic(fmt.Sprintf("invalid less function: %T", lessFunc)) + } + ms := mapSorter{vf.Type().In(0), vf} + return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort)) +} + +type mapSorter struct { + in reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (ms mapSorter) filter(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + return (x != nil && y != nil && vx.Type() == vy.Type()) && + (vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) && + (vx.Len() != 0 || vy.Len() != 0) +} +func (ms mapSorter) sort(x interface{}) interface{} { + src := reflect.ValueOf(x) + outType := reflect.StructOf([]reflect.StructField{ + {Name: "K", Type: src.Type().Key()}, + {Name: "V", Type: src.Type().Elem()}, + }) + dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len()) + for i, k := range src.MapKeys() { + v := reflect.New(outType).Elem() + v.Field(0).Set(k) + v.Field(1).Set(src.MapIndex(k)) + dst.Index(i).Set(v) + } + sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) }) + ms.checkSort(dst) + return dst.Interface() +} +func (ms mapSorter) checkSort(v reflect.Value) { + for i := 1; i < v.Len(); i++ { + if !ms.less(v, i-1, i) { + panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i))) + } + } +} +func (ms mapSorter) less(v reflect.Value, i, j int) bool { + vx, vy := v.Index(i).Field(0), v.Index(j).Field(0) + return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool() +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go new file mode 100644 index 00000000..dae7ced5 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go @@ -0,0 +1,187 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp" +) + +// filterField returns a new Option where opt is only evaluated on paths that +// include a specific exported field on a single struct type. +// The struct type is specified by passing in a value of that type. +// +// The name may be a dot-delimited string (e.g., "Foo.Bar") to select a +// specific sub-field that is embedded or nested within the parent struct. +func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option { + // TODO: This is currently unexported over concerns of how helper filters + // can be composed together easily. + // TODO: Add tests for FilterField. + + sf := newStructFilter(typ, name) + return cmp.FilterPath(sf.filter, opt) +} + +type structFilter struct { + t reflect.Type // The root struct type to match on + ft fieldTree // Tree of fields to match on +} + +func newStructFilter(typ interface{}, names ...string) structFilter { + // TODO: Perhaps allow * as a special identifier to allow ignoring any + // number of path steps until the next field match? + // This could be useful when a concrete struct gets transformed into + // an anonymous struct where it is not possible to specify that by type, + // but the transformer happens to provide guarantees about the names of + // the transformed fields. + + t := reflect.TypeOf(typ) + if t == nil || t.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T must be a struct", typ)) + } + var ft fieldTree + for _, name := range names { + cname, err := canonicalName(t, name) + if err != nil { + panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err)) + } + ft.insert(cname) + } + return structFilter{t, ft} +} + +func (sf structFilter) filter(p cmp.Path) bool { + for i, ps := range p { + if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) { + return true + } + } + return false +} + +// fieldTree represents a set of dot-separated identifiers. +// +// For example, inserting the following selectors: +// Foo +// Foo.Bar.Baz +// Foo.Buzz +// Nuka.Cola.Quantum +// +// Results in a tree of the form: +// {sub: { +// "Foo": {ok: true, sub: { +// "Bar": {sub: { +// "Baz": {ok: true}, +// }}, +// "Buzz": {ok: true}, +// }}, +// "Nuka": {sub: { +// "Cola": {sub: { +// "Quantum": {ok: true}, +// }}, +// }}, +// }} +type fieldTree struct { + ok bool // Whether this is a specified node + sub map[string]fieldTree // The sub-tree of fields under this node +} + +// insert inserts a sequence of field accesses into the tree. +func (ft *fieldTree) insert(cname []string) { + if ft.sub == nil { + ft.sub = make(map[string]fieldTree) + } + if len(cname) == 0 { + ft.ok = true + return + } + sub := ft.sub[cname[0]] + sub.insert(cname[1:]) + ft.sub[cname[0]] = sub +} + +// matchPrefix reports whether any selector in the fieldTree matches +// the start of path p. +func (ft fieldTree) matchPrefix(p cmp.Path) bool { + for _, ps := range p { + switch ps := ps.(type) { + case cmp.StructField: + ft = ft.sub[ps.Name()] + if ft.ok { + return true + } + if len(ft.sub) == 0 { + return false + } + case cmp.Indirect: + default: + return false + } + } + return false +} + +// canonicalName returns a list of identifiers where any struct field access +// through an embedded field is expanded to include the names of the embedded +// types themselves. +// +// For example, suppose field "Foo" is not directly in the parent struct, +// but actually from an embedded struct of type "Bar". Then, the canonical name +// of "Foo" is actually "Bar.Foo". +// +// Suppose field "Foo" is not directly in the parent struct, but actually +// a field in two different embedded structs of types "Bar" and "Baz". +// Then the selector "Foo" causes a panic since it is ambiguous which one it +// refers to. The user must specify either "Bar.Foo" or "Baz.Foo". +func canonicalName(t reflect.Type, sel string) ([]string, error) { + var name string + sel = strings.TrimPrefix(sel, ".") + if sel == "" { + return nil, fmt.Errorf("name must not be empty") + } + if i := strings.IndexByte(sel, '.'); i < 0 { + name, sel = sel, "" + } else { + name, sel = sel[:i], sel[i:] + } + + // Type must be a struct or pointer to struct. + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return nil, fmt.Errorf("%v must be a struct", t) + } + + // Find the canonical name for this current field name. + // If the field exists in an embedded struct, then it will be expanded. + sf, _ := t.FieldByName(name) + if !isExported(name) { + // Avoid using reflect.Type.FieldByName for unexported fields due to + // buggy behavior with regard to embeddeding and unexported fields. + // See https://golang.org/issue/4876 for details. + sf = reflect.StructField{} + for i := 0; i < t.NumField() && sf.Name == ""; i++ { + if t.Field(i).Name == name { + sf = t.Field(i) + } + } + } + if sf.Name == "" { + return []string{name}, fmt.Errorf("does not exist") + } + var ss []string + for i := range sf.Index { + ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name) + } + if sel == "" { + return ss, nil + } + ssPost, err := canonicalName(sf.Type, sel) + return append(ss, ssPost...), err +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go new file mode 100644 index 00000000..9d651553 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go @@ -0,0 +1,35 @@ +// Copyright 2018, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "github.com/google/go-cmp/cmp" +) + +type xformFilter struct{ xform cmp.Option } + +func (xf xformFilter) filter(p cmp.Path) bool { + for _, ps := range p { + if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform { + return false + } + } + return true +} + +// AcyclicTransformer returns a Transformer with a filter applied that ensures +// that the transformer cannot be recursively applied upon its own output. +// +// An example use case is a transformer that splits a string by lines: +// AcyclicTransformer("SplitLines", func(s string) []string{ +// return strings.Split(s, "\n") +// }) +// +// Had this been an unfiltered Transformer instead, this would result in an +// infinite cycle converting a string to []string to [][]string and so on. +func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option { + xf := xformFilter{cmp.Transformer(name, xformFunc)} + return cmp.FilterPath(xf.filter, xf.xform) +} diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go new file mode 100644 index 00000000..580ae209 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/compare.go @@ -0,0 +1,682 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// Package cmp determines equality of values. +// +// This package is intended to be a more powerful and safer alternative to +// reflect.DeepEqual for comparing whether two values are semantically equal. +// It is intended to only be used in tests, as performance is not a goal and +// it may panic if it cannot compare the values. Its propensity towards +// panicking means that its unsuitable for production environments where a +// spurious panic may be fatal. +// +// The primary features of cmp are: +// +// • When the default behavior of equality does not suit the needs of the test, +// custom equality functions can override the equality operation. +// For example, an equality function may report floats as equal so long as they +// are within some tolerance of each other. +// +// • Types that have an Equal method may use that method to determine equality. +// This allows package authors to determine the equality operation for the types +// that they define. +// +// • If no custom equality functions are used and no Equal method is defined, +// equality is determined by recursively comparing the primitive kinds on both +// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported +// fields are not compared by default; they result in panics unless suppressed +// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly +// compared using the Exporter option. +package cmp + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp/internal/diff" + "github.com/google/go-cmp/cmp/internal/flags" + "github.com/google/go-cmp/cmp/internal/function" + "github.com/google/go-cmp/cmp/internal/value" +) + +// Equal reports whether x and y are equal by recursively applying the +// following rules in the given order to x and y and all of their sub-values: +// +// • Let S be the set of all Ignore, Transformer, and Comparer options that +// remain after applying all path filters, value filters, and type filters. +// If at least one Ignore exists in S, then the comparison is ignored. +// If the number of Transformer and Comparer options in S is greater than one, +// then Equal panics because it is ambiguous which option to use. +// If S contains a single Transformer, then use that to transform the current +// values and recursively call Equal on the output values. +// If S contains a single Comparer, then use that to compare the current values. +// Otherwise, evaluation proceeds to the next rule. +// +// • If the values have an Equal method of the form "(T) Equal(T) bool" or +// "(T) Equal(I) bool" where T is assignable to I, then use the result of +// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and +// evaluation proceeds to the next rule. +// +// • Lastly, try to compare x and y based on their basic kinds. +// Simple kinds like booleans, integers, floats, complex numbers, strings, and +// channels are compared using the equivalent of the == operator in Go. +// Functions are only equal if they are both nil, otherwise they are unequal. +// +// Structs are equal if recursively calling Equal on all fields report equal. +// If a struct contains unexported fields, Equal panics unless an Ignore option +// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option +// explicitly permits comparing the unexported field. +// +// Slices are equal if they are both nil or both non-nil, where recursively +// calling Equal on all non-ignored slice or array elements report equal. +// Empty non-nil slices and nil slices are not equal; to equate empty slices, +// consider using cmpopts.EquateEmpty. +// +// Maps are equal if they are both nil or both non-nil, where recursively +// calling Equal on all non-ignored map entries report equal. +// Map keys are equal according to the == operator. +// To use custom comparisons for map keys, consider using cmpopts.SortMaps. +// Empty non-nil maps and nil maps are not equal; to equate empty maps, +// consider using cmpopts.EquateEmpty. +// +// Pointers and interfaces are equal if they are both nil or both non-nil, +// where they have the same underlying concrete type and recursively +// calling Equal on the underlying values reports equal. +// +// Before recursing into a pointer, slice element, or map, the current path +// is checked to detect whether the address has already been visited. +// If there is a cycle, then the pointed at values are considered equal +// only if both addresses were previously visited in the same path step. +func Equal(x, y interface{}, opts ...Option) bool { + s := newState(opts) + s.compareAny(rootStep(x, y)) + return s.result.Equal() +} + +// Diff returns a human-readable report of the differences between two values. +// It returns an empty string if and only if Equal returns true for the same +// input values and options. +// +// The output is displayed as a literal in pseudo-Go syntax. +// At the start of each line, a "-" prefix indicates an element removed from x, +// a "+" prefix to indicates an element added to y, and the lack of a prefix +// indicates an element common to both x and y. If possible, the output +// uses fmt.Stringer.String or error.Error methods to produce more humanly +// readable outputs. In such cases, the string is prefixed with either an +// 's' or 'e' character, respectively, to indicate that the method was called. +// +// Do not depend on this output being stable. If you need the ability to +// programmatically interpret the difference, consider using a custom Reporter. +func Diff(x, y interface{}, opts ...Option) string { + s := newState(opts) + + // Optimization: If there are no other reporters, we can optimize for the + // common case where the result is equal (and thus no reported difference). + // This avoids the expensive construction of a difference tree. + if len(s.reporters) == 0 { + s.compareAny(rootStep(x, y)) + if s.result.Equal() { + return "" + } + s.result = diff.Result{} // Reset results + } + + r := new(defaultReporter) + s.reporters = append(s.reporters, reporter{r}) + s.compareAny(rootStep(x, y)) + d := r.String() + if (d == "") != s.result.Equal() { + panic("inconsistent difference and equality results") + } + return d +} + +// rootStep constructs the first path step. If x and y have differing types, +// then they are stored within an empty interface type. +func rootStep(x, y interface{}) PathStep { + vx := reflect.ValueOf(x) + vy := reflect.ValueOf(y) + + // If the inputs are different types, auto-wrap them in an empty interface + // so that they have the same parent type. + var t reflect.Type + if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() { + t = reflect.TypeOf((*interface{})(nil)).Elem() + if vx.IsValid() { + vvx := reflect.New(t).Elem() + vvx.Set(vx) + vx = vvx + } + if vy.IsValid() { + vvy := reflect.New(t).Elem() + vvy.Set(vy) + vy = vvy + } + } else { + t = vx.Type() + } + + return &pathStep{t, vx, vy} +} + +type state struct { + // These fields represent the "comparison state". + // Calling statelessCompare must not result in observable changes to these. + result diff.Result // The current result of comparison + curPath Path // The current path in the value tree + curPtrs pointerPath // The current set of visited pointers + reporters []reporter // Optional reporters + + // recChecker checks for infinite cycles applying the same set of + // transformers upon the output of itself. + recChecker recChecker + + // dynChecker triggers pseudo-random checks for option correctness. + // It is safe for statelessCompare to mutate this value. + dynChecker dynChecker + + // These fields, once set by processOption, will not change. + exporters []exporter // List of exporters for structs with unexported fields + opts Options // List of all fundamental and filter options +} + +func newState(opts []Option) *state { + // Always ensure a validator option exists to validate the inputs. + s := &state{opts: Options{validator{}}} + s.curPtrs.Init() + s.processOption(Options(opts)) + return s +} + +func (s *state) processOption(opt Option) { + switch opt := opt.(type) { + case nil: + case Options: + for _, o := range opt { + s.processOption(o) + } + case coreOption: + type filtered interface { + isFiltered() bool + } + if fopt, ok := opt.(filtered); ok && !fopt.isFiltered() { + panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt)) + } + s.opts = append(s.opts, opt) + case exporter: + s.exporters = append(s.exporters, opt) + case reporter: + s.reporters = append(s.reporters, opt) + default: + panic(fmt.Sprintf("unknown option %T", opt)) + } +} + +// statelessCompare compares two values and returns the result. +// This function is stateless in that it does not alter the current result, +// or output to any registered reporters. +func (s *state) statelessCompare(step PathStep) diff.Result { + // We do not save and restore curPath and curPtrs because all of the + // compareX methods should properly push and pop from them. + // It is an implementation bug if the contents of the paths differ from + // when calling this function to when returning from it. + + oldResult, oldReporters := s.result, s.reporters + s.result = diff.Result{} // Reset result + s.reporters = nil // Remove reporters to avoid spurious printouts + s.compareAny(step) + res := s.result + s.result, s.reporters = oldResult, oldReporters + return res +} + +func (s *state) compareAny(step PathStep) { + // Update the path stack. + s.curPath.push(step) + defer s.curPath.pop() + for _, r := range s.reporters { + r.PushStep(step) + defer r.PopStep() + } + s.recChecker.Check(s.curPath) + + // Cycle-detection for slice elements (see NOTE in compareSlice). + t := step.Type() + vx, vy := step.Values() + if si, ok := step.(SliceIndex); ok && si.isSlice && vx.IsValid() && vy.IsValid() { + px, py := vx.Addr(), vy.Addr() + if eq, visited := s.curPtrs.Push(px, py); visited { + s.report(eq, reportByCycle) + return + } + defer s.curPtrs.Pop(px, py) + } + + // Rule 1: Check whether an option applies on this node in the value tree. + if s.tryOptions(t, vx, vy) { + return + } + + // Rule 2: Check whether the type has a valid Equal method. + if s.tryMethod(t, vx, vy) { + return + } + + // Rule 3: Compare based on the underlying kind. + switch t.Kind() { + case reflect.Bool: + s.report(vx.Bool() == vy.Bool(), 0) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s.report(vx.Int() == vy.Int(), 0) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s.report(vx.Uint() == vy.Uint(), 0) + case reflect.Float32, reflect.Float64: + s.report(vx.Float() == vy.Float(), 0) + case reflect.Complex64, reflect.Complex128: + s.report(vx.Complex() == vy.Complex(), 0) + case reflect.String: + s.report(vx.String() == vy.String(), 0) + case reflect.Chan, reflect.UnsafePointer: + s.report(vx.Pointer() == vy.Pointer(), 0) + case reflect.Func: + s.report(vx.IsNil() && vy.IsNil(), 0) + case reflect.Struct: + s.compareStruct(t, vx, vy) + case reflect.Slice, reflect.Array: + s.compareSlice(t, vx, vy) + case reflect.Map: + s.compareMap(t, vx, vy) + case reflect.Ptr: + s.comparePtr(t, vx, vy) + case reflect.Interface: + s.compareInterface(t, vx, vy) + default: + panic(fmt.Sprintf("%v kind not handled", t.Kind())) + } +} + +func (s *state) tryOptions(t reflect.Type, vx, vy reflect.Value) bool { + // Evaluate all filters and apply the remaining options. + if opt := s.opts.filter(s, t, vx, vy); opt != nil { + opt.apply(s, vx, vy) + return true + } + return false +} + +func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool { + // Check if this type even has an Equal method. + m, ok := t.MethodByName("Equal") + if !ok || !function.IsType(m.Type, function.EqualAssignable) { + return false + } + + eq := s.callTTBFunc(m.Func, vx, vy) + s.report(eq, reportByMethod) + return true +} + +func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value { + v = sanitizeValue(v, f.Type().In(0)) + if !s.dynChecker.Next() { + return f.Call([]reflect.Value{v})[0] + } + + // Run the function twice and ensure that we get the same results back. + // We run in goroutines so that the race detector (if enabled) can detect + // unsafe mutations to the input. + c := make(chan reflect.Value) + go detectRaces(c, f, v) + got := <-c + want := f.Call([]reflect.Value{v})[0] + if step.vx, step.vy = got, want; !s.statelessCompare(step).Equal() { + // To avoid false-positives with non-reflexive equality operations, + // we sanity check whether a value is equal to itself. + if step.vx, step.vy = want, want; !s.statelessCompare(step).Equal() { + return want + } + panic(fmt.Sprintf("non-deterministic function detected: %s", function.NameOf(f))) + } + return want +} + +func (s *state) callTTBFunc(f, x, y reflect.Value) bool { + x = sanitizeValue(x, f.Type().In(0)) + y = sanitizeValue(y, f.Type().In(1)) + if !s.dynChecker.Next() { + return f.Call([]reflect.Value{x, y})[0].Bool() + } + + // Swapping the input arguments is sufficient to check that + // f is symmetric and deterministic. + // We run in goroutines so that the race detector (if enabled) can detect + // unsafe mutations to the input. + c := make(chan reflect.Value) + go detectRaces(c, f, y, x) + got := <-c + want := f.Call([]reflect.Value{x, y})[0].Bool() + if !got.IsValid() || got.Bool() != want { + panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", function.NameOf(f))) + } + return want +} + +func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) { + var ret reflect.Value + defer func() { + recover() // Ignore panics, let the other call to f panic instead + c <- ret + }() + ret = f.Call(vs)[0] +} + +// sanitizeValue converts nil interfaces of type T to those of type R, +// assuming that T is assignable to R. +// Otherwise, it returns the input value as is. +func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value { + // TODO(≥go1.10): Workaround for reflect bug (https://golang.org/issue/22143). + if !flags.AtLeastGo110 { + if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t { + return reflect.New(t).Elem() + } + } + return v +} + +func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { + var addr bool + var vax, vay reflect.Value // Addressable versions of vx and vy + + var mayForce, mayForceInit bool + step := StructField{&structField{}} + for i := 0; i < t.NumField(); i++ { + step.typ = t.Field(i).Type + step.vx = vx.Field(i) + step.vy = vy.Field(i) + step.name = t.Field(i).Name + step.idx = i + step.unexported = !isExported(step.name) + if step.unexported { + if step.name == "_" { + continue + } + // Defer checking of unexported fields until later to give an + // Ignore a chance to ignore the field. + if !vax.IsValid() || !vay.IsValid() { + // For retrieveUnexportedField to work, the parent struct must + // be addressable. Create a new copy of the values if + // necessary to make them addressable. + addr = vx.CanAddr() || vy.CanAddr() + vax = makeAddressable(vx) + vay = makeAddressable(vy) + } + if !mayForceInit { + for _, xf := range s.exporters { + mayForce = mayForce || xf(t) + } + mayForceInit = true + } + step.mayForce = mayForce + step.paddr = addr + step.pvx = vax + step.pvy = vay + step.field = t.Field(i) + } + s.compareAny(step) + } +} + +func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) { + isSlice := t.Kind() == reflect.Slice + if isSlice && (vx.IsNil() || vy.IsNil()) { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + + // NOTE: It is incorrect to call curPtrs.Push on the slice header pointer + // since slices represents a list of pointers, rather than a single pointer. + // The pointer checking logic must be handled on a per-element basis + // in compareAny. + // + // A slice header (see reflect.SliceHeader) in Go is a tuple of a starting + // pointer P, a length N, and a capacity C. Supposing each slice element has + // a memory size of M, then the slice is equivalent to the list of pointers: + // [P+i*M for i in range(N)] + // + // For example, v[:0] and v[:1] are slices with the same starting pointer, + // but they are clearly different values. Using the slice pointer alone + // violates the assumption that equal pointers implies equal values. + + step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}, isSlice: isSlice}} + withIndexes := func(ix, iy int) SliceIndex { + if ix >= 0 { + step.vx, step.xkey = vx.Index(ix), ix + } else { + step.vx, step.xkey = reflect.Value{}, -1 + } + if iy >= 0 { + step.vy, step.ykey = vy.Index(iy), iy + } else { + step.vy, step.ykey = reflect.Value{}, -1 + } + return step + } + + // Ignore options are able to ignore missing elements in a slice. + // However, detecting these reliably requires an optimal differencing + // algorithm, for which diff.Difference is not. + // + // Instead, we first iterate through both slices to detect which elements + // would be ignored if standing alone. The index of non-discarded elements + // are stored in a separate slice, which diffing is then performed on. + var indexesX, indexesY []int + var ignoredX, ignoredY []bool + for ix := 0; ix < vx.Len(); ix++ { + ignored := s.statelessCompare(withIndexes(ix, -1)).NumDiff == 0 + if !ignored { + indexesX = append(indexesX, ix) + } + ignoredX = append(ignoredX, ignored) + } + for iy := 0; iy < vy.Len(); iy++ { + ignored := s.statelessCompare(withIndexes(-1, iy)).NumDiff == 0 + if !ignored { + indexesY = append(indexesY, iy) + } + ignoredY = append(ignoredY, ignored) + } + + // Compute an edit-script for slices vx and vy (excluding ignored elements). + edits := diff.Difference(len(indexesX), len(indexesY), func(ix, iy int) diff.Result { + return s.statelessCompare(withIndexes(indexesX[ix], indexesY[iy])) + }) + + // Replay the ignore-scripts and the edit-script. + var ix, iy int + for ix < vx.Len() || iy < vy.Len() { + var e diff.EditType + switch { + case ix < len(ignoredX) && ignoredX[ix]: + e = diff.UniqueX + case iy < len(ignoredY) && ignoredY[iy]: + e = diff.UniqueY + default: + e, edits = edits[0], edits[1:] + } + switch e { + case diff.UniqueX: + s.compareAny(withIndexes(ix, -1)) + ix++ + case diff.UniqueY: + s.compareAny(withIndexes(-1, iy)) + iy++ + default: + s.compareAny(withIndexes(ix, iy)) + ix++ + iy++ + } + } +} + +func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) { + if vx.IsNil() || vy.IsNil() { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + + // Cycle-detection for maps. + if eq, visited := s.curPtrs.Push(vx, vy); visited { + s.report(eq, reportByCycle) + return + } + defer s.curPtrs.Pop(vx, vy) + + // We combine and sort the two map keys so that we can perform the + // comparisons in a deterministic order. + step := MapIndex{&mapIndex{pathStep: pathStep{typ: t.Elem()}}} + for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) { + step.vx = vx.MapIndex(k) + step.vy = vy.MapIndex(k) + step.key = k + if !step.vx.IsValid() && !step.vy.IsValid() { + // It is possible for both vx and vy to be invalid if the + // key contained a NaN value in it. + // + // Even with the ability to retrieve NaN keys in Go 1.12, + // there still isn't a sensible way to compare the values since + // a NaN key may map to multiple unordered values. + // The most reasonable way to compare NaNs would be to compare the + // set of values. However, this is impossible to do efficiently + // since set equality is provably an O(n^2) operation given only + // an Equal function. If we had a Less function or Hash function, + // this could be done in O(n*log(n)) or O(n), respectively. + // + // Rather than adding complex logic to deal with NaNs, make it + // the user's responsibility to compare such obscure maps. + const help = "consider providing a Comparer to compare the map" + panic(fmt.Sprintf("%#v has map key with NaNs\n%s", s.curPath, help)) + } + s.compareAny(step) + } +} + +func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) { + if vx.IsNil() || vy.IsNil() { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + + // Cycle-detection for pointers. + if eq, visited := s.curPtrs.Push(vx, vy); visited { + s.report(eq, reportByCycle) + return + } + defer s.curPtrs.Pop(vx, vy) + + vx, vy = vx.Elem(), vy.Elem() + s.compareAny(Indirect{&indirect{pathStep{t.Elem(), vx, vy}}}) +} + +func (s *state) compareInterface(t reflect.Type, vx, vy reflect.Value) { + if vx.IsNil() || vy.IsNil() { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + vx, vy = vx.Elem(), vy.Elem() + if vx.Type() != vy.Type() { + s.report(false, 0) + return + } + s.compareAny(TypeAssertion{&typeAssertion{pathStep{vx.Type(), vx, vy}}}) +} + +func (s *state) report(eq bool, rf resultFlags) { + if rf&reportByIgnore == 0 { + if eq { + s.result.NumSame++ + rf |= reportEqual + } else { + s.result.NumDiff++ + rf |= reportUnequal + } + } + for _, r := range s.reporters { + r.Report(Result{flags: rf}) + } +} + +// recChecker tracks the state needed to periodically perform checks that +// user provided transformers are not stuck in an infinitely recursive cycle. +type recChecker struct{ next int } + +// Check scans the Path for any recursive transformers and panics when any +// recursive transformers are detected. Note that the presence of a +// recursive Transformer does not necessarily imply an infinite cycle. +// As such, this check only activates after some minimal number of path steps. +func (rc *recChecker) Check(p Path) { + const minLen = 1 << 16 + if rc.next == 0 { + rc.next = minLen + } + if len(p) < rc.next { + return + } + rc.next <<= 1 + + // Check whether the same transformer has appeared at least twice. + var ss []string + m := map[Option]int{} + for _, ps := range p { + if t, ok := ps.(Transform); ok { + t := t.Option() + if m[t] == 1 { // Transformer was used exactly once before + tf := t.(*transformer).fnc.Type() + ss = append(ss, fmt.Sprintf("%v: %v => %v", t, tf.In(0), tf.Out(0))) + } + m[t]++ + } + } + if len(ss) > 0 { + const warning = "recursive set of Transformers detected" + const help = "consider using cmpopts.AcyclicTransformer" + set := strings.Join(ss, "\n\t") + panic(fmt.Sprintf("%s:\n\t%s\n%s", warning, set, help)) + } +} + +// dynChecker tracks the state needed to periodically perform checks that +// user provided functions are symmetric and deterministic. +// The zero value is safe for immediate use. +type dynChecker struct{ curr, next int } + +// Next increments the state and reports whether a check should be performed. +// +// Checks occur every Nth function call, where N is a triangular number: +// 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ... +// See https://en.wikipedia.org/wiki/Triangular_number +// +// This sequence ensures that the cost of checks drops significantly as +// the number of functions calls grows larger. +func (dc *dynChecker) Next() bool { + ok := dc.curr == dc.next + if ok { + dc.curr = 0 + dc.next++ + } + dc.curr++ + return ok +} + +// makeAddressable returns a value that is always addressable. +// It returns the input verbatim if it is already addressable, +// otherwise it creates a new value and returns an addressable copy. +func makeAddressable(v reflect.Value) reflect.Value { + if v.CanAddr() { + return v + } + vc := reflect.New(v.Type()).Elem() + vc.Set(v) + return vc +} diff --git a/vendor/github.com/google/go-cmp/cmp/export_panic.go b/vendor/github.com/google/go-cmp/cmp/export_panic.go new file mode 100644 index 00000000..dfa5d213 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/export_panic.go @@ -0,0 +1,15 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build purego + +package cmp + +import "reflect" + +const supportExporters = false + +func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value { + panic("no support for forcibly accessing unexported fields") +} diff --git a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go new file mode 100644 index 00000000..351f1a34 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go @@ -0,0 +1,35 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build !purego + +package cmp + +import ( + "reflect" + "unsafe" +) + +const supportExporters = true + +// retrieveUnexportedField uses unsafe to forcibly retrieve any field from +// a struct such that the value has read-write permissions. +// +// The parent struct, v, must be addressable, while f must be a StructField +// describing the field to retrieve. If addr is false, +// then the returned value will be shallowed copied to be non-addressable. +func retrieveUnexportedField(v reflect.Value, f reflect.StructField, addr bool) reflect.Value { + ve := reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem() + if !addr { + // A field is addressable if and only if the struct is addressable. + // If the original parent value was not addressable, shallow copy the + // value to make it non-addressable to avoid leaking an implementation + // detail of how forcibly exporting a field works. + if ve.Kind() == reflect.Interface && ve.IsNil() { + return reflect.Zero(f.Type) + } + return reflect.ValueOf(ve.Interface()).Convert(f.Type) + } + return ve +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go new file mode 100644 index 00000000..fe98dcc6 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go @@ -0,0 +1,17 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build !cmp_debug + +package diff + +var debug debugger + +type debugger struct{} + +func (debugger) Begin(_, _ int, f EqualFunc, _, _ *EditScript) EqualFunc { + return f +} +func (debugger) Update() {} +func (debugger) Finish() {} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go new file mode 100644 index 00000000..597b6ae5 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go @@ -0,0 +1,122 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build cmp_debug + +package diff + +import ( + "fmt" + "strings" + "sync" + "time" +) + +// The algorithm can be seen running in real-time by enabling debugging: +// go test -tags=cmp_debug -v +// +// Example output: +// === RUN TestDifference/#34 +// ┌───────────────────────────────┐ +// │ \ · · · · · · · · · · · · · · │ +// │ · # · · · · · · · · · · · · · │ +// │ · \ · · · · · · · · · · · · · │ +// │ · · \ · · · · · · · · · · · · │ +// │ · · · X # · · · · · · · · · · │ +// │ · · · # \ · · · · · · · · · · │ +// │ · · · · · # # · · · · · · · · │ +// │ · · · · · # \ · · · · · · · · │ +// │ · · · · · · · \ · · · · · · · │ +// │ · · · · · · · · \ · · · · · · │ +// │ · · · · · · · · · \ · · · · · │ +// │ · · · · · · · · · · \ · · # · │ +// │ · · · · · · · · · · · \ # # · │ +// │ · · · · · · · · · · · # # # · │ +// │ · · · · · · · · · · # # # # · │ +// │ · · · · · · · · · # # # # # · │ +// │ · · · · · · · · · · · · · · \ │ +// └───────────────────────────────┘ +// [.Y..M.XY......YXYXY.|] +// +// The grid represents the edit-graph where the horizontal axis represents +// list X and the vertical axis represents list Y. The start of the two lists +// is the top-left, while the ends are the bottom-right. The '·' represents +// an unexplored node in the graph. The '\' indicates that the two symbols +// from list X and Y are equal. The 'X' indicates that two symbols are similar +// (but not exactly equal) to each other. The '#' indicates that the two symbols +// are different (and not similar). The algorithm traverses this graph trying to +// make the paths starting in the top-left and the bottom-right connect. +// +// The series of '.', 'X', 'Y', and 'M' characters at the bottom represents +// the currently established path from the forward and reverse searches, +// separated by a '|' character. + +const ( + updateDelay = 100 * time.Millisecond + finishDelay = 500 * time.Millisecond + ansiTerminal = true // ANSI escape codes used to move terminal cursor +) + +var debug debugger + +type debugger struct { + sync.Mutex + p1, p2 EditScript + fwdPath, revPath *EditScript + grid []byte + lines int +} + +func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc { + dbg.Lock() + dbg.fwdPath, dbg.revPath = p1, p2 + top := "┌─" + strings.Repeat("──", nx) + "┐\n" + row := "│ " + strings.Repeat("· ", nx) + "│\n" + btm := "└─" + strings.Repeat("──", nx) + "┘\n" + dbg.grid = []byte(top + strings.Repeat(row, ny) + btm) + dbg.lines = strings.Count(dbg.String(), "\n") + fmt.Print(dbg) + + // Wrap the EqualFunc so that we can intercept each result. + return func(ix, iy int) (r Result) { + cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("· ")*ix:][:len("·")] + for i := range cell { + cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot + } + switch r = f(ix, iy); { + case r.Equal(): + cell[0] = '\\' + case r.Similar(): + cell[0] = 'X' + default: + cell[0] = '#' + } + return + } +} + +func (dbg *debugger) Update() { + dbg.print(updateDelay) +} + +func (dbg *debugger) Finish() { + dbg.print(finishDelay) + dbg.Unlock() +} + +func (dbg *debugger) String() string { + dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0] + for i := len(*dbg.revPath) - 1; i >= 0; i-- { + dbg.p2 = append(dbg.p2, (*dbg.revPath)[i]) + } + return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2) +} + +func (dbg *debugger) print(d time.Duration) { + if ansiTerminal { + fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor + } + fmt.Print(dbg) + time.Sleep(d) +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go new file mode 100644 index 00000000..730e223e --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go @@ -0,0 +1,392 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// Package diff implements an algorithm for producing edit-scripts. +// The edit-script is a sequence of operations needed to transform one list +// of symbols into another (or vice-versa). The edits allowed are insertions, +// deletions, and modifications. The summation of all edits is called the +// Levenshtein distance as this problem is well-known in computer science. +// +// This package prioritizes performance over accuracy. That is, the run time +// is more important than obtaining a minimal Levenshtein distance. +package diff + +import ( + "math/rand" + "time" + + "github.com/google/go-cmp/cmp/internal/flags" +) + +// EditType represents a single operation within an edit-script. +type EditType uint8 + +const ( + // Identity indicates that a symbol pair is identical in both list X and Y. + Identity EditType = iota + // UniqueX indicates that a symbol only exists in X and not Y. + UniqueX + // UniqueY indicates that a symbol only exists in Y and not X. + UniqueY + // Modified indicates that a symbol pair is a modification of each other. + Modified +) + +// EditScript represents the series of differences between two lists. +type EditScript []EditType + +// String returns a human-readable string representing the edit-script where +// Identity, UniqueX, UniqueY, and Modified are represented by the +// '.', 'X', 'Y', and 'M' characters, respectively. +func (es EditScript) String() string { + b := make([]byte, len(es)) + for i, e := range es { + switch e { + case Identity: + b[i] = '.' + case UniqueX: + b[i] = 'X' + case UniqueY: + b[i] = 'Y' + case Modified: + b[i] = 'M' + default: + panic("invalid edit-type") + } + } + return string(b) +} + +// stats returns a histogram of the number of each type of edit operation. +func (es EditScript) stats() (s struct{ NI, NX, NY, NM int }) { + for _, e := range es { + switch e { + case Identity: + s.NI++ + case UniqueX: + s.NX++ + case UniqueY: + s.NY++ + case Modified: + s.NM++ + default: + panic("invalid edit-type") + } + } + return +} + +// Dist is the Levenshtein distance and is guaranteed to be 0 if and only if +// lists X and Y are equal. +func (es EditScript) Dist() int { return len(es) - es.stats().NI } + +// LenX is the length of the X list. +func (es EditScript) LenX() int { return len(es) - es.stats().NY } + +// LenY is the length of the Y list. +func (es EditScript) LenY() int { return len(es) - es.stats().NX } + +// EqualFunc reports whether the symbols at indexes ix and iy are equal. +// When called by Difference, the index is guaranteed to be within nx and ny. +type EqualFunc func(ix int, iy int) Result + +// Result is the result of comparison. +// NumSame is the number of sub-elements that are equal. +// NumDiff is the number of sub-elements that are not equal. +type Result struct{ NumSame, NumDiff int } + +// BoolResult returns a Result that is either Equal or not Equal. +func BoolResult(b bool) Result { + if b { + return Result{NumSame: 1} // Equal, Similar + } else { + return Result{NumDiff: 2} // Not Equal, not Similar + } +} + +// Equal indicates whether the symbols are equal. Two symbols are equal +// if and only if NumDiff == 0. If Equal, then they are also Similar. +func (r Result) Equal() bool { return r.NumDiff == 0 } + +// Similar indicates whether two symbols are similar and may be represented +// by using the Modified type. As a special case, we consider binary comparisons +// (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar. +// +// The exact ratio of NumSame to NumDiff to determine similarity may change. +func (r Result) Similar() bool { + // Use NumSame+1 to offset NumSame so that binary comparisons are similar. + return r.NumSame+1 >= r.NumDiff +} + +var randInt = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) + +// Difference reports whether two lists of lengths nx and ny are equal +// given the definition of equality provided as f. +// +// This function returns an edit-script, which is a sequence of operations +// needed to convert one list into the other. The following invariants for +// the edit-script are maintained: +// • eq == (es.Dist()==0) +// • nx == es.LenX() +// • ny == es.LenY() +// +// This algorithm is not guaranteed to be an optimal solution (i.e., one that +// produces an edit-script with a minimal Levenshtein distance). This algorithm +// favors performance over optimality. The exact output is not guaranteed to +// be stable and may change over time. +func Difference(nx, ny int, f EqualFunc) (es EditScript) { + // This algorithm is based on traversing what is known as an "edit-graph". + // See Figure 1 from "An O(ND) Difference Algorithm and Its Variations" + // by Eugene W. Myers. Since D can be as large as N itself, this is + // effectively O(N^2). Unlike the algorithm from that paper, we are not + // interested in the optimal path, but at least some "decent" path. + // + // For example, let X and Y be lists of symbols: + // X = [A B C A B B A] + // Y = [C B A B A C] + // + // The edit-graph can be drawn as the following: + // A B C A B B A + // ┌─────────────┐ + // C │_|_|\|_|_|_|_│ 0 + // B │_|\|_|_|\|\|_│ 1 + // A │\|_|_|\|_|_|\│ 2 + // B │_|\|_|_|\|\|_│ 3 + // A │\|_|_|\|_|_|\│ 4 + // C │ | |\| | | | │ 5 + // └─────────────┘ 6 + // 0 1 2 3 4 5 6 7 + // + // List X is written along the horizontal axis, while list Y is written + // along the vertical axis. At any point on this grid, if the symbol in + // list X matches the corresponding symbol in list Y, then a '\' is drawn. + // The goal of any minimal edit-script algorithm is to find a path from the + // top-left corner to the bottom-right corner, while traveling through the + // fewest horizontal or vertical edges. + // A horizontal edge is equivalent to inserting a symbol from list X. + // A vertical edge is equivalent to inserting a symbol from list Y. + // A diagonal edge is equivalent to a matching symbol between both X and Y. + + // To ensure flexibility in changing the algorithm in the future, + // introduce some degree of deliberate instability. + // This is achieved by fiddling the zigzag iterator to start searching + // the graph starting from the bottom-right versus than the top-left. + // The result may differ depending on the starting search location, + // but still produces a valid edit script. + zigzagInit := randInt // either 0 or 1 + if flags.Deterministic { + zigzagInit = 0 + } + + // Invariants: + // • 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx + // • 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny + // + // In general: + // • fwdFrontier.X < revFrontier.X + // • fwdFrontier.Y < revFrontier.Y + // Unless, it is time for the algorithm to terminate. + fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} + revPath := path{-1, point{nx, ny}, make(EditScript, 0)} + fwdFrontier := fwdPath.point // Forward search frontier + revFrontier := revPath.point // Reverse search frontier + + // Search budget bounds the cost of searching for better paths. + // The longest sequence of non-matching symbols that can be tolerated is + // approximately the square-root of the search budget. + searchBudget := 4 * (nx + ny) // O(n) + + // The algorithm below is a greedy, meet-in-the-middle algorithm for + // computing sub-optimal edit-scripts between two lists. + // + // The algorithm is approximately as follows: + // • Searching for differences switches back-and-forth between + // a search that starts at the beginning (the top-left corner), and + // a search that starts at the end (the bottom-right corner). The goal of + // the search is connect with the search from the opposite corner. + // • As we search, we build a path in a greedy manner, where the first + // match seen is added to the path (this is sub-optimal, but provides a + // decent result in practice). When matches are found, we try the next pair + // of symbols in the lists and follow all matches as far as possible. + // • When searching for matches, we search along a diagonal going through + // through the "frontier" point. If no matches are found, we advance the + // frontier towards the opposite corner. + // • This algorithm terminates when either the X coordinates or the + // Y coordinates of the forward and reverse frontier points ever intersect. + // + // This algorithm is correct even if searching only in the forward direction + // or in the reverse direction. We do both because it is commonly observed + // that two lists commonly differ because elements were added to the front + // or end of the other list. + // + // Running the tests with the "cmp_debug" build tag prints a visualization + // of the algorithm running in real-time. This is educational for + // understanding how the algorithm works. See debug_enable.go. + f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) + for { + // Forward search from the beginning. + if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { + break + } + for stop1, stop2, i := false, false, zigzagInit; !(stop1 && stop2) && searchBudget > 0; i++ { + // Search in a diagonal pattern for a match. + z := zigzag(i) + p := point{fwdFrontier.X + z, fwdFrontier.Y - z} + switch { + case p.X >= revPath.X || p.Y < fwdPath.Y: + stop1 = true // Hit top-right corner + case p.Y >= revPath.Y || p.X < fwdPath.X: + stop2 = true // Hit bottom-left corner + case f(p.X, p.Y).Equal(): + // Match found, so connect the path to this point. + fwdPath.connect(p, f) + fwdPath.append(Identity) + // Follow sequence of matches as far as possible. + for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { + if !f(fwdPath.X, fwdPath.Y).Equal() { + break + } + fwdPath.append(Identity) + } + fwdFrontier = fwdPath.point + stop1, stop2 = true, true + default: + searchBudget-- // Match not found + } + debug.Update() + } + // Advance the frontier towards reverse point. + if revPath.X-fwdFrontier.X >= revPath.Y-fwdFrontier.Y { + fwdFrontier.X++ + } else { + fwdFrontier.Y++ + } + + // Reverse search from the end. + if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { + break + } + for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { + // Search in a diagonal pattern for a match. + z := zigzag(i) + p := point{revFrontier.X - z, revFrontier.Y + z} + switch { + case fwdPath.X >= p.X || revPath.Y < p.Y: + stop1 = true // Hit bottom-left corner + case fwdPath.Y >= p.Y || revPath.X < p.X: + stop2 = true // Hit top-right corner + case f(p.X-1, p.Y-1).Equal(): + // Match found, so connect the path to this point. + revPath.connect(p, f) + revPath.append(Identity) + // Follow sequence of matches as far as possible. + for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { + if !f(revPath.X-1, revPath.Y-1).Equal() { + break + } + revPath.append(Identity) + } + revFrontier = revPath.point + stop1, stop2 = true, true + default: + searchBudget-- // Match not found + } + debug.Update() + } + // Advance the frontier towards forward point. + if revFrontier.X-fwdPath.X >= revFrontier.Y-fwdPath.Y { + revFrontier.X-- + } else { + revFrontier.Y-- + } + } + + // Join the forward and reverse paths and then append the reverse path. + fwdPath.connect(revPath.point, f) + for i := len(revPath.es) - 1; i >= 0; i-- { + t := revPath.es[i] + revPath.es = revPath.es[:i] + fwdPath.append(t) + } + debug.Finish() + return fwdPath.es +} + +type path struct { + dir int // +1 if forward, -1 if reverse + point // Leading point of the EditScript path + es EditScript +} + +// connect appends any necessary Identity, Modified, UniqueX, or UniqueY types +// to the edit-script to connect p.point to dst. +func (p *path) connect(dst point, f EqualFunc) { + if p.dir > 0 { + // Connect in forward direction. + for dst.X > p.X && dst.Y > p.Y { + switch r := f(p.X, p.Y); { + case r.Equal(): + p.append(Identity) + case r.Similar(): + p.append(Modified) + case dst.X-p.X >= dst.Y-p.Y: + p.append(UniqueX) + default: + p.append(UniqueY) + } + } + for dst.X > p.X { + p.append(UniqueX) + } + for dst.Y > p.Y { + p.append(UniqueY) + } + } else { + // Connect in reverse direction. + for p.X > dst.X && p.Y > dst.Y { + switch r := f(p.X-1, p.Y-1); { + case r.Equal(): + p.append(Identity) + case r.Similar(): + p.append(Modified) + case p.Y-dst.Y >= p.X-dst.X: + p.append(UniqueY) + default: + p.append(UniqueX) + } + } + for p.X > dst.X { + p.append(UniqueX) + } + for p.Y > dst.Y { + p.append(UniqueY) + } + } +} + +func (p *path) append(t EditType) { + p.es = append(p.es, t) + switch t { + case Identity, Modified: + p.add(p.dir, p.dir) + case UniqueX: + p.add(p.dir, 0) + case UniqueY: + p.add(0, p.dir) + } + debug.Update() +} + +type point struct{ X, Y int } + +func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } + +// zigzag maps a consecutive sequence of integers to a zig-zag sequence. +// [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] +func zigzag(x int) int { + if x&1 != 0 { + x = ^x + } + return x >> 1 +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go new file mode 100644 index 00000000..a9e7fc0b --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go @@ -0,0 +1,9 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package flags + +// Deterministic controls whether the output of Diff should be deterministic. +// This is only used for testing. +var Deterministic bool diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go new file mode 100644 index 00000000..01aed0a1 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go @@ -0,0 +1,10 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build !go1.10 + +package flags + +// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. +const AtLeastGo110 = false diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go new file mode 100644 index 00000000..c0b667f5 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go @@ -0,0 +1,10 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build go1.10 + +package flags + +// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. +const AtLeastGo110 = true diff --git a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go new file mode 100644 index 00000000..ace1dbe8 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go @@ -0,0 +1,99 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// Package function provides functionality for identifying function types. +package function + +import ( + "reflect" + "regexp" + "runtime" + "strings" +) + +type funcType int + +const ( + _ funcType = iota + + tbFunc // func(T) bool + ttbFunc // func(T, T) bool + trbFunc // func(T, R) bool + tibFunc // func(T, I) bool + trFunc // func(T) R + + Equal = ttbFunc // func(T, T) bool + EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool + Transformer = trFunc // func(T) R + ValueFilter = ttbFunc // func(T, T) bool + Less = ttbFunc // func(T, T) bool + ValuePredicate = tbFunc // func(T) bool + KeyValuePredicate = trbFunc // func(T, R) bool +) + +var boolType = reflect.TypeOf(true) + +// IsType reports whether the reflect.Type is of the specified function type. +func IsType(t reflect.Type, ft funcType) bool { + if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { + return false + } + ni, no := t.NumIn(), t.NumOut() + switch ft { + case tbFunc: // func(T) bool + if ni == 1 && no == 1 && t.Out(0) == boolType { + return true + } + case ttbFunc: // func(T, T) bool + if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { + return true + } + case trbFunc: // func(T, R) bool + if ni == 2 && no == 1 && t.Out(0) == boolType { + return true + } + case tibFunc: // func(T, I) bool + if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { + return true + } + case trFunc: // func(T) R + if ni == 1 && no == 1 { + return true + } + } + return false +} + +var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) + +// NameOf returns the name of the function value. +func NameOf(v reflect.Value) string { + fnc := runtime.FuncForPC(v.Pointer()) + if fnc == nil { + return "" + } + fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" + + // Method closures have a "-fm" suffix. + fullName = strings.TrimSuffix(fullName, "-fm") + + var name string + for len(fullName) > 0 { + inParen := strings.HasSuffix(fullName, ")") + fullName = strings.TrimSuffix(fullName, ")") + + s := lastIdentRx.FindString(fullName) + if s == "" { + break + } + name = s + "." + name + fullName = strings.TrimSuffix(fullName, s) + + if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { + fullName = fullName[:i] + } + fullName = strings.TrimSuffix(fullName, ".") + } + return strings.TrimSuffix(name, ".") +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/name.go b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go new file mode 100644 index 00000000..8228e7d5 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go @@ -0,0 +1,157 @@ +// Copyright 2020, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package value + +import ( + "reflect" + "strconv" +) + +// TypeString is nearly identical to reflect.Type.String, +// but has an additional option to specify that full type names be used. +func TypeString(t reflect.Type, qualified bool) string { + return string(appendTypeName(nil, t, qualified, false)) +} + +func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte { + // BUG: Go reflection provides no way to disambiguate two named types + // of the same name and within the same package, + // but declared within the namespace of different functions. + + // Named type. + if t.Name() != "" { + if qualified && t.PkgPath() != "" { + b = append(b, '"') + b = append(b, t.PkgPath()...) + b = append(b, '"') + b = append(b, '.') + b = append(b, t.Name()...) + } else { + b = append(b, t.String()...) + } + return b + } + + // Unnamed type. + switch k := t.Kind(); k { + case reflect.Bool, reflect.String, reflect.UnsafePointer, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + b = append(b, k.String()...) + case reflect.Chan: + if t.ChanDir() == reflect.RecvDir { + b = append(b, "<-"...) + } + b = append(b, "chan"...) + if t.ChanDir() == reflect.SendDir { + b = append(b, "<-"...) + } + b = append(b, ' ') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Func: + if !elideFunc { + b = append(b, "func"...) + } + b = append(b, '(') + for i := 0; i < t.NumIn(); i++ { + if i > 0 { + b = append(b, ", "...) + } + if i == t.NumIn()-1 && t.IsVariadic() { + b = append(b, "..."...) + b = appendTypeName(b, t.In(i).Elem(), qualified, false) + } else { + b = appendTypeName(b, t.In(i), qualified, false) + } + } + b = append(b, ')') + switch t.NumOut() { + case 0: + // Do nothing + case 1: + b = append(b, ' ') + b = appendTypeName(b, t.Out(0), qualified, false) + default: + b = append(b, " ("...) + for i := 0; i < t.NumOut(); i++ { + if i > 0 { + b = append(b, ", "...) + } + b = appendTypeName(b, t.Out(i), qualified, false) + } + b = append(b, ')') + } + case reflect.Struct: + b = append(b, "struct{ "...) + for i := 0; i < t.NumField(); i++ { + if i > 0 { + b = append(b, "; "...) + } + sf := t.Field(i) + if !sf.Anonymous { + if qualified && sf.PkgPath != "" { + b = append(b, '"') + b = append(b, sf.PkgPath...) + b = append(b, '"') + b = append(b, '.') + } + b = append(b, sf.Name...) + b = append(b, ' ') + } + b = appendTypeName(b, sf.Type, qualified, false) + if sf.Tag != "" { + b = append(b, ' ') + b = strconv.AppendQuote(b, string(sf.Tag)) + } + } + if b[len(b)-1] == ' ' { + b = b[:len(b)-1] + } else { + b = append(b, ' ') + } + b = append(b, '}') + case reflect.Slice, reflect.Array: + b = append(b, '[') + if k == reflect.Array { + b = strconv.AppendUint(b, uint64(t.Len()), 10) + } + b = append(b, ']') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Map: + b = append(b, "map["...) + b = appendTypeName(b, t.Key(), qualified, false) + b = append(b, ']') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Ptr: + b = append(b, '*') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Interface: + b = append(b, "interface{ "...) + for i := 0; i < t.NumMethod(); i++ { + if i > 0 { + b = append(b, "; "...) + } + m := t.Method(i) + if qualified && m.PkgPath != "" { + b = append(b, '"') + b = append(b, m.PkgPath...) + b = append(b, '"') + b = append(b, '.') + } + b = append(b, m.Name...) + b = appendTypeName(b, m.Type, qualified, true) + } + if b[len(b)-1] == ' ' { + b = b[:len(b)-1] + } else { + b = append(b, ' ') + } + b = append(b, '}') + default: + panic("invalid kind: " + k.String()) + } + return b +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go new file mode 100644 index 00000000..e9e384a1 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go @@ -0,0 +1,33 @@ +// Copyright 2018, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build purego + +package value + +import "reflect" + +// Pointer is an opaque typed pointer and is guaranteed to be comparable. +type Pointer struct { + p uintptr + t reflect.Type +} + +// PointerOf returns a Pointer from v, which must be a +// reflect.Ptr, reflect.Slice, or reflect.Map. +func PointerOf(v reflect.Value) Pointer { + // NOTE: Storing a pointer as an uintptr is technically incorrect as it + // assumes that the GC implementation does not use a moving collector. + return Pointer{v.Pointer(), v.Type()} +} + +// IsNil reports whether the pointer is nil. +func (p Pointer) IsNil() bool { + return p.p == 0 +} + +// Uintptr returns the pointer as a uintptr. +func (p Pointer) Uintptr() uintptr { + return p.p +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go new file mode 100644 index 00000000..b50c17ec --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go @@ -0,0 +1,36 @@ +// Copyright 2018, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build !purego + +package value + +import ( + "reflect" + "unsafe" +) + +// Pointer is an opaque typed pointer and is guaranteed to be comparable. +type Pointer struct { + p unsafe.Pointer + t reflect.Type +} + +// PointerOf returns a Pointer from v, which must be a +// reflect.Ptr, reflect.Slice, or reflect.Map. +func PointerOf(v reflect.Value) Pointer { + // The proper representation of a pointer is unsafe.Pointer, + // which is necessary if the GC ever uses a moving collector. + return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} +} + +// IsNil reports whether the pointer is nil. +func (p Pointer) IsNil() bool { + return p.p == nil +} + +// Uintptr returns the pointer as a uintptr. +func (p Pointer) Uintptr() uintptr { + return uintptr(p.p) +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go new file mode 100644 index 00000000..24fbae6e --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go @@ -0,0 +1,106 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package value + +import ( + "fmt" + "math" + "reflect" + "sort" +) + +// SortKeys sorts a list of map keys, deduplicating keys if necessary. +// The type of each value must be comparable. +func SortKeys(vs []reflect.Value) []reflect.Value { + if len(vs) == 0 { + return vs + } + + // Sort the map keys. + sort.SliceStable(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) }) + + // Deduplicate keys (fails for NaNs). + vs2 := vs[:1] + for _, v := range vs[1:] { + if isLess(vs2[len(vs2)-1], v) { + vs2 = append(vs2, v) + } + } + return vs2 +} + +// isLess is a generic function for sorting arbitrary map keys. +// The inputs must be of the same type and must be comparable. +func isLess(x, y reflect.Value) bool { + switch x.Type().Kind() { + case reflect.Bool: + return !x.Bool() && y.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return x.Int() < y.Int() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return x.Uint() < y.Uint() + case reflect.Float32, reflect.Float64: + // NOTE: This does not sort -0 as less than +0 + // since Go maps treat -0 and +0 as equal keys. + fx, fy := x.Float(), y.Float() + return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy) + case reflect.Complex64, reflect.Complex128: + cx, cy := x.Complex(), y.Complex() + rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy) + if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) { + return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy) + } + return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry) + case reflect.Ptr, reflect.UnsafePointer, reflect.Chan: + return x.Pointer() < y.Pointer() + case reflect.String: + return x.String() < y.String() + case reflect.Array: + for i := 0; i < x.Len(); i++ { + if isLess(x.Index(i), y.Index(i)) { + return true + } + if isLess(y.Index(i), x.Index(i)) { + return false + } + } + return false + case reflect.Struct: + for i := 0; i < x.NumField(); i++ { + if isLess(x.Field(i), y.Field(i)) { + return true + } + if isLess(y.Field(i), x.Field(i)) { + return false + } + } + return false + case reflect.Interface: + vx, vy := x.Elem(), y.Elem() + if !vx.IsValid() || !vy.IsValid() { + return !vx.IsValid() && vy.IsValid() + } + tx, ty := vx.Type(), vy.Type() + if tx == ty { + return isLess(x.Elem(), y.Elem()) + } + if tx.Kind() != ty.Kind() { + return vx.Kind() < vy.Kind() + } + if tx.String() != ty.String() { + return tx.String() < ty.String() + } + if tx.PkgPath() != ty.PkgPath() { + return tx.PkgPath() < ty.PkgPath() + } + // This can happen in rare situations, so we fallback to just comparing + // the unique pointer for a reflect.Type. This guarantees deterministic + // ordering within a program, but it is obviously not stable. + return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer() + default: + // Must be Func, Map, or Slice; which are not comparable. + panic(fmt.Sprintf("%T is not comparable", x.Type())) + } +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go new file mode 100644 index 00000000..06a8ffd0 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go @@ -0,0 +1,48 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package value + +import ( + "math" + "reflect" +) + +// IsZero reports whether v is the zero value. +// This does not rely on Interface and so can be used on unexported fields. +func IsZero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return v.Bool() == false + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return math.Float64bits(v.Float()) == 0 + case reflect.Complex64, reflect.Complex128: + return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0 + case reflect.String: + return v.String() == "" + case reflect.UnsafePointer: + return v.Pointer() == 0 + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + return v.IsNil() + case reflect.Array: + for i := 0; i < v.Len(); i++ { + if !IsZero(v.Index(i)) { + return false + } + } + return true + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + if !IsZero(v.Field(i)) { + return false + } + } + return true + } + return false +} diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go new file mode 100644 index 00000000..abbd2a63 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/options.go @@ -0,0 +1,549 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import ( + "fmt" + "reflect" + "regexp" + "strings" + + "github.com/google/go-cmp/cmp/internal/function" +) + +// Option configures for specific behavior of Equal and Diff. In particular, +// the fundamental Option functions (Ignore, Transformer, and Comparer), +// configure how equality is determined. +// +// The fundamental options may be composed with filters (FilterPath and +// FilterValues) to control the scope over which they are applied. +// +// The cmp/cmpopts package provides helper functions for creating options that +// may be used with Equal and Diff. +type Option interface { + // filter applies all filters and returns the option that remains. + // Each option may only read s.curPath and call s.callTTBFunc. + // + // An Options is returned only if multiple comparers or transformers + // can apply simultaneously and will only contain values of those types + // or sub-Options containing values of those types. + filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption +} + +// applicableOption represents the following types: +// Fundamental: ignore | validator | *comparer | *transformer +// Grouping: Options +type applicableOption interface { + Option + + // apply executes the option, which may mutate s or panic. + apply(s *state, vx, vy reflect.Value) +} + +// coreOption represents the following types: +// Fundamental: ignore | validator | *comparer | *transformer +// Filters: *pathFilter | *valuesFilter +type coreOption interface { + Option + isCore() +} + +type core struct{} + +func (core) isCore() {} + +// Options is a list of Option values that also satisfies the Option interface. +// Helper comparison packages may return an Options value when packing multiple +// Option values into a single Option. When this package processes an Options, +// it will be implicitly expanded into a flat list. +// +// Applying a filter on an Options is equivalent to applying that same filter +// on all individual options held within. +type Options []Option + +func (opts Options) filter(s *state, t reflect.Type, vx, vy reflect.Value) (out applicableOption) { + for _, opt := range opts { + switch opt := opt.filter(s, t, vx, vy); opt.(type) { + case ignore: + return ignore{} // Only ignore can short-circuit evaluation + case validator: + out = validator{} // Takes precedence over comparer or transformer + case *comparer, *transformer, Options: + switch out.(type) { + case nil: + out = opt + case validator: + // Keep validator + case *comparer, *transformer, Options: + out = Options{out, opt} // Conflicting comparers or transformers + } + } + } + return out +} + +func (opts Options) apply(s *state, _, _ reflect.Value) { + const warning = "ambiguous set of applicable options" + const help = "consider using filters to ensure at most one Comparer or Transformer may apply" + var ss []string + for _, opt := range flattenOptions(nil, opts) { + ss = append(ss, fmt.Sprint(opt)) + } + set := strings.Join(ss, "\n\t") + panic(fmt.Sprintf("%s at %#v:\n\t%s\n%s", warning, s.curPath, set, help)) +} + +func (opts Options) String() string { + var ss []string + for _, opt := range opts { + ss = append(ss, fmt.Sprint(opt)) + } + return fmt.Sprintf("Options{%s}", strings.Join(ss, ", ")) +} + +// FilterPath returns a new Option where opt is only evaluated if filter f +// returns true for the current Path in the value tree. +// +// This filter is called even if a slice element or map entry is missing and +// provides an opportunity to ignore such cases. The filter function must be +// symmetric such that the filter result is identical regardless of whether the +// missing value is from x or y. +// +// The option passed in may be an Ignore, Transformer, Comparer, Options, or +// a previously filtered Option. +func FilterPath(f func(Path) bool, opt Option) Option { + if f == nil { + panic("invalid path filter function") + } + if opt := normalizeOption(opt); opt != nil { + return &pathFilter{fnc: f, opt: opt} + } + return nil +} + +type pathFilter struct { + core + fnc func(Path) bool + opt Option +} + +func (f pathFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { + if f.fnc(s.curPath) { + return f.opt.filter(s, t, vx, vy) + } + return nil +} + +func (f pathFilter) String() string { + return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt) +} + +// FilterValues returns a new Option where opt is only evaluated if filter f, +// which is a function of the form "func(T, T) bool", returns true for the +// current pair of values being compared. If either value is invalid or +// the type of the values is not assignable to T, then this filter implicitly +// returns false. +// +// The filter function must be +// symmetric (i.e., agnostic to the order of the inputs) and +// deterministic (i.e., produces the same result when given the same inputs). +// If T is an interface, it is possible that f is called with two values with +// different concrete types that both implement T. +// +// The option passed in may be an Ignore, Transformer, Comparer, Options, or +// a previously filtered Option. +func FilterValues(f interface{}, opt Option) Option { + v := reflect.ValueOf(f) + if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { + panic(fmt.Sprintf("invalid values filter function: %T", f)) + } + if opt := normalizeOption(opt); opt != nil { + vf := &valuesFilter{fnc: v, opt: opt} + if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { + vf.typ = ti + } + return vf + } + return nil +} + +type valuesFilter struct { + core + typ reflect.Type // T + fnc reflect.Value // func(T, T) bool + opt Option +} + +func (f valuesFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { + if !vx.IsValid() || !vx.CanInterface() || !vy.IsValid() || !vy.CanInterface() { + return nil + } + if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) { + return f.opt.filter(s, t, vx, vy) + } + return nil +} + +func (f valuesFilter) String() string { + return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt) +} + +// Ignore is an Option that causes all comparisons to be ignored. +// This value is intended to be combined with FilterPath or FilterValues. +// It is an error to pass an unfiltered Ignore option to Equal. +func Ignore() Option { return ignore{} } + +type ignore struct{ core } + +func (ignore) isFiltered() bool { return false } +func (ignore) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { return ignore{} } +func (ignore) apply(s *state, _, _ reflect.Value) { s.report(true, reportByIgnore) } +func (ignore) String() string { return "Ignore()" } + +// validator is a sentinel Option type to indicate that some options could not +// be evaluated due to unexported fields, missing slice elements, or +// missing map entries. Both values are validator only for unexported fields. +type validator struct{ core } + +func (validator) filter(_ *state, _ reflect.Type, vx, vy reflect.Value) applicableOption { + if !vx.IsValid() || !vy.IsValid() { + return validator{} + } + if !vx.CanInterface() || !vy.CanInterface() { + return validator{} + } + return nil +} +func (validator) apply(s *state, vx, vy reflect.Value) { + // Implies missing slice element or map entry. + if !vx.IsValid() || !vy.IsValid() { + s.report(vx.IsValid() == vy.IsValid(), 0) + return + } + + // Unable to Interface implies unexported field without visibility access. + if !vx.CanInterface() || !vy.CanInterface() { + const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported" + var name string + if t := s.curPath.Index(-2).Type(); t.Name() != "" { + // Named type with unexported fields. + name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType + } else { + // Unnamed type with unexported fields. Derive PkgPath from field. + var pkgPath string + for i := 0; i < t.NumField() && pkgPath == ""; i++ { + pkgPath = t.Field(i).PkgPath + } + name = fmt.Sprintf("%q.(%v)", pkgPath, t.String()) // e.g., "path/to/package".(struct { a int }) + } + panic(fmt.Sprintf("cannot handle unexported field at %#v:\n\t%v\n%s", s.curPath, name, help)) + } + + panic("not reachable") +} + +// identRx represents a valid identifier according to the Go specification. +const identRx = `[_\p{L}][_\p{L}\p{N}]*` + +var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) + +// Transformer returns an Option that applies a transformation function that +// converts values of a certain type into that of another. +// +// The transformer f must be a function "func(T) R" that converts values of +// type T to those of type R and is implicitly filtered to input values +// assignable to T. The transformer must not mutate T in any way. +// +// To help prevent some cases of infinite recursive cycles applying the +// same transform to the output of itself (e.g., in the case where the +// input and output types are the same), an implicit filter is added such that +// a transformer is applicable only if that exact transformer is not already +// in the tail of the Path since the last non-Transform step. +// For situations where the implicit filter is still insufficient, +// consider using cmpopts.AcyclicTransformer, which adds a filter +// to prevent the transformer from being recursively applied upon itself. +// +// The name is a user provided label that is used as the Transform.Name in the +// transformation PathStep (and eventually shown in the Diff output). +// The name must be a valid identifier or qualified identifier in Go syntax. +// If empty, an arbitrary name is used. +func Transformer(name string, f interface{}) Option { + v := reflect.ValueOf(f) + if !function.IsType(v.Type(), function.Transformer) || v.IsNil() { + panic(fmt.Sprintf("invalid transformer function: %T", f)) + } + if name == "" { + name = function.NameOf(v) + if !identsRx.MatchString(name) { + name = "λ" // Lambda-symbol as placeholder name + } + } else if !identsRx.MatchString(name) { + panic(fmt.Sprintf("invalid name: %q", name)) + } + tr := &transformer{name: name, fnc: reflect.ValueOf(f)} + if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { + tr.typ = ti + } + return tr +} + +type transformer struct { + core + name string + typ reflect.Type // T + fnc reflect.Value // func(T) R +} + +func (tr *transformer) isFiltered() bool { return tr.typ != nil } + +func (tr *transformer) filter(s *state, t reflect.Type, _, _ reflect.Value) applicableOption { + for i := len(s.curPath) - 1; i >= 0; i-- { + if t, ok := s.curPath[i].(Transform); !ok { + break // Hit most recent non-Transform step + } else if tr == t.trans { + return nil // Cannot directly use same Transform + } + } + if tr.typ == nil || t.AssignableTo(tr.typ) { + return tr + } + return nil +} + +func (tr *transformer) apply(s *state, vx, vy reflect.Value) { + step := Transform{&transform{pathStep{typ: tr.fnc.Type().Out(0)}, tr}} + vvx := s.callTRFunc(tr.fnc, vx, step) + vvy := s.callTRFunc(tr.fnc, vy, step) + step.vx, step.vy = vvx, vvy + s.compareAny(step) +} + +func (tr transformer) String() string { + return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc)) +} + +// Comparer returns an Option that determines whether two values are equal +// to each other. +// +// The comparer f must be a function "func(T, T) bool" and is implicitly +// filtered to input values assignable to T. If T is an interface, it is +// possible that f is called with two values of different concrete types that +// both implement T. +// +// The equality function must be: +// • Symmetric: equal(x, y) == equal(y, x) +// • Deterministic: equal(x, y) == equal(x, y) +// • Pure: equal(x, y) does not modify x or y +func Comparer(f interface{}) Option { + v := reflect.ValueOf(f) + if !function.IsType(v.Type(), function.Equal) || v.IsNil() { + panic(fmt.Sprintf("invalid comparer function: %T", f)) + } + cm := &comparer{fnc: v} + if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { + cm.typ = ti + } + return cm +} + +type comparer struct { + core + typ reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (cm *comparer) isFiltered() bool { return cm.typ != nil } + +func (cm *comparer) filter(_ *state, t reflect.Type, _, _ reflect.Value) applicableOption { + if cm.typ == nil || t.AssignableTo(cm.typ) { + return cm + } + return nil +} + +func (cm *comparer) apply(s *state, vx, vy reflect.Value) { + eq := s.callTTBFunc(cm.fnc, vx, vy) + s.report(eq, reportByFunc) +} + +func (cm comparer) String() string { + return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc)) +} + +// Exporter returns an Option that specifies whether Equal is allowed to +// introspect into the unexported fields of certain struct types. +// +// Users of this option must understand that comparing on unexported fields +// from external packages is not safe since changes in the internal +// implementation of some external package may cause the result of Equal +// to unexpectedly change. However, it may be valid to use this option on types +// defined in an internal package where the semantic meaning of an unexported +// field is in the control of the user. +// +// In many cases, a custom Comparer should be used instead that defines +// equality as a function of the public API of a type rather than the underlying +// unexported implementation. +// +// For example, the reflect.Type documentation defines equality to be determined +// by the == operator on the interface (essentially performing a shallow pointer +// comparison) and most attempts to compare *regexp.Regexp types are interested +// in only checking that the regular expression strings are equal. +// Both of these are accomplished using Comparers: +// +// Comparer(func(x, y reflect.Type) bool { return x == y }) +// Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) +// +// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore +// all unexported fields on specified struct types. +func Exporter(f func(reflect.Type) bool) Option { + if !supportExporters { + panic("Exporter is not supported on purego builds") + } + return exporter(f) +} + +type exporter func(reflect.Type) bool + +func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { + panic("not implemented") +} + +// AllowUnexported returns an Options that allows Equal to forcibly introspect +// unexported fields of the specified struct types. +// +// See Exporter for the proper use of this option. +func AllowUnexported(types ...interface{}) Option { + m := make(map[reflect.Type]bool) + for _, typ := range types { + t := reflect.TypeOf(typ) + if t.Kind() != reflect.Struct { + panic(fmt.Sprintf("invalid struct type: %T", typ)) + } + m[t] = true + } + return exporter(func(t reflect.Type) bool { return m[t] }) +} + +// Result represents the comparison result for a single node and +// is provided by cmp when calling Result (see Reporter). +type Result struct { + _ [0]func() // Make Result incomparable + flags resultFlags +} + +// Equal reports whether the node was determined to be equal or not. +// As a special case, ignored nodes are considered equal. +func (r Result) Equal() bool { + return r.flags&(reportEqual|reportByIgnore) != 0 +} + +// ByIgnore reports whether the node is equal because it was ignored. +// This never reports true if Equal reports false. +func (r Result) ByIgnore() bool { + return r.flags&reportByIgnore != 0 +} + +// ByMethod reports whether the Equal method determined equality. +func (r Result) ByMethod() bool { + return r.flags&reportByMethod != 0 +} + +// ByFunc reports whether a Comparer function determined equality. +func (r Result) ByFunc() bool { + return r.flags&reportByFunc != 0 +} + +// ByCycle reports whether a reference cycle was detected. +func (r Result) ByCycle() bool { + return r.flags&reportByCycle != 0 +} + +type resultFlags uint + +const ( + _ resultFlags = (1 << iota) / 2 + + reportEqual + reportUnequal + reportByIgnore + reportByMethod + reportByFunc + reportByCycle +) + +// Reporter is an Option that can be passed to Equal. When Equal traverses +// the value trees, it calls PushStep as it descends into each node in the +// tree and PopStep as it ascend out of the node. The leaves of the tree are +// either compared (determined to be equal or not equal) or ignored and reported +// as such by calling the Report method. +func Reporter(r interface { + // PushStep is called when a tree-traversal operation is performed. + // The PathStep itself is only valid until the step is popped. + // The PathStep.Values are valid for the duration of the entire traversal + // and must not be mutated. + // + // Equal always calls PushStep at the start to provide an operation-less + // PathStep used to report the root values. + // + // Within a slice, the exact set of inserted, removed, or modified elements + // is unspecified and may change in future implementations. + // The entries of a map are iterated through in an unspecified order. + PushStep(PathStep) + + // Report is called exactly once on leaf nodes to report whether the + // comparison identified the node as equal, unequal, or ignored. + // A leaf node is one that is immediately preceded by and followed by + // a pair of PushStep and PopStep calls. + Report(Result) + + // PopStep ascends back up the value tree. + // There is always a matching pop call for every push call. + PopStep() +}) Option { + return reporter{r} +} + +type reporter struct{ reporterIface } +type reporterIface interface { + PushStep(PathStep) + Report(Result) + PopStep() +} + +func (reporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { + panic("not implemented") +} + +// normalizeOption normalizes the input options such that all Options groups +// are flattened and groups with a single element are reduced to that element. +// Only coreOptions and Options containing coreOptions are allowed. +func normalizeOption(src Option) Option { + switch opts := flattenOptions(nil, Options{src}); len(opts) { + case 0: + return nil + case 1: + return opts[0] + default: + return opts + } +} + +// flattenOptions copies all options in src to dst as a flat list. +// Only coreOptions and Options containing coreOptions are allowed. +func flattenOptions(dst, src Options) Options { + for _, opt := range src { + switch opt := opt.(type) { + case nil: + continue + case Options: + dst = flattenOptions(dst, opt) + case coreOption: + dst = append(dst, opt) + default: + panic(fmt.Sprintf("invalid option type: %T", opt)) + } + } + return dst +} diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go new file mode 100644 index 00000000..603dbb00 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/path.go @@ -0,0 +1,378 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import ( + "fmt" + "reflect" + "strings" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/value" +) + +// Path is a list of PathSteps describing the sequence of operations to get +// from some root type to the current position in the value tree. +// The first Path element is always an operation-less PathStep that exists +// simply to identify the initial type. +// +// When traversing structs with embedded structs, the embedded struct will +// always be accessed as a field before traversing the fields of the +// embedded struct themselves. That is, an exported field from the +// embedded struct will never be accessed directly from the parent struct. +type Path []PathStep + +// PathStep is a union-type for specific operations to traverse +// a value's tree structure. Users of this package never need to implement +// these types as values of this type will be returned by this package. +// +// Implementations of this interface are +// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. +type PathStep interface { + String() string + + // Type is the resulting type after performing the path step. + Type() reflect.Type + + // Values is the resulting values after performing the path step. + // The type of each valid value is guaranteed to be identical to Type. + // + // In some cases, one or both may be invalid or have restrictions: + // • For StructField, both are not interface-able if the current field + // is unexported and the struct type is not explicitly permitted by + // an Exporter to traverse unexported fields. + // • For SliceIndex, one may be invalid if an element is missing from + // either the x or y slice. + // • For MapIndex, one may be invalid if an entry is missing from + // either the x or y map. + // + // The provided values must not be mutated. + Values() (vx, vy reflect.Value) +} + +var ( + _ PathStep = StructField{} + _ PathStep = SliceIndex{} + _ PathStep = MapIndex{} + _ PathStep = Indirect{} + _ PathStep = TypeAssertion{} + _ PathStep = Transform{} +) + +func (pa *Path) push(s PathStep) { + *pa = append(*pa, s) +} + +func (pa *Path) pop() { + *pa = (*pa)[:len(*pa)-1] +} + +// Last returns the last PathStep in the Path. +// If the path is empty, this returns a non-nil PathStep that reports a nil Type. +func (pa Path) Last() PathStep { + return pa.Index(-1) +} + +// Index returns the ith step in the Path and supports negative indexing. +// A negative index starts counting from the tail of the Path such that -1 +// refers to the last step, -2 refers to the second-to-last step, and so on. +// If index is invalid, this returns a non-nil PathStep that reports a nil Type. +func (pa Path) Index(i int) PathStep { + if i < 0 { + i = len(pa) + i + } + if i < 0 || i >= len(pa) { + return pathStep{} + } + return pa[i] +} + +// String returns the simplified path to a node. +// The simplified path only contains struct field accesses. +// +// For example: +// MyMap.MySlices.MyField +func (pa Path) String() string { + var ss []string + for _, s := range pa { + if _, ok := s.(StructField); ok { + ss = append(ss, s.String()) + } + } + return strings.TrimPrefix(strings.Join(ss, ""), ".") +} + +// GoString returns the path to a specific node using Go syntax. +// +// For example: +// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField +func (pa Path) GoString() string { + var ssPre, ssPost []string + var numIndirect int + for i, s := range pa { + var nextStep PathStep + if i+1 < len(pa) { + nextStep = pa[i+1] + } + switch s := s.(type) { + case Indirect: + numIndirect++ + pPre, pPost := "(", ")" + switch nextStep.(type) { + case Indirect: + continue // Next step is indirection, so let them batch up + case StructField: + numIndirect-- // Automatic indirection on struct fields + case nil: + pPre, pPost = "", "" // Last step; no need for parenthesis + } + if numIndirect > 0 { + ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect)) + ssPost = append(ssPost, pPost) + } + numIndirect = 0 + continue + case Transform: + ssPre = append(ssPre, s.trans.name+"(") + ssPost = append(ssPost, ")") + continue + } + ssPost = append(ssPost, s.String()) + } + for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 { + ssPre[i], ssPre[j] = ssPre[j], ssPre[i] + } + return strings.Join(ssPre, "") + strings.Join(ssPost, "") +} + +type pathStep struct { + typ reflect.Type + vx, vy reflect.Value +} + +func (ps pathStep) Type() reflect.Type { return ps.typ } +func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy } +func (ps pathStep) String() string { + if ps.typ == nil { + return "" + } + s := ps.typ.String() + if s == "" || strings.ContainsAny(s, "{}\n") { + return "root" // Type too simple or complex to print + } + return fmt.Sprintf("{%s}", s) +} + +// StructField represents a struct field access on a field called Name. +type StructField struct{ *structField } +type structField struct { + pathStep + name string + idx int + + // These fields are used for forcibly accessing an unexported field. + // pvx, pvy, and field are only valid if unexported is true. + unexported bool + mayForce bool // Forcibly allow visibility + paddr bool // Was parent addressable? + pvx, pvy reflect.Value // Parent values (always addressible) + field reflect.StructField // Field information +} + +func (sf StructField) Type() reflect.Type { return sf.typ } +func (sf StructField) Values() (vx, vy reflect.Value) { + if !sf.unexported { + return sf.vx, sf.vy // CanInterface reports true + } + + // Forcibly obtain read-write access to an unexported struct field. + if sf.mayForce { + vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr) + vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr) + return vx, vy // CanInterface reports true + } + return sf.vx, sf.vy // CanInterface reports false +} +func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } + +// Name is the field name. +func (sf StructField) Name() string { return sf.name } + +// Index is the index of the field in the parent struct type. +// See reflect.Type.Field. +func (sf StructField) Index() int { return sf.idx } + +// SliceIndex is an index operation on a slice or array at some index Key. +type SliceIndex struct{ *sliceIndex } +type sliceIndex struct { + pathStep + xkey, ykey int + isSlice bool // False for reflect.Array +} + +func (si SliceIndex) Type() reflect.Type { return si.typ } +func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy } +func (si SliceIndex) String() string { + switch { + case si.xkey == si.ykey: + return fmt.Sprintf("[%d]", si.xkey) + case si.ykey == -1: + // [5->?] means "I don't know where X[5] went" + return fmt.Sprintf("[%d->?]", si.xkey) + case si.xkey == -1: + // [?->3] means "I don't know where Y[3] came from" + return fmt.Sprintf("[?->%d]", si.ykey) + default: + // [5->3] means "X[5] moved to Y[3]" + return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) + } +} + +// Key is the index key; it may return -1 if in a split state +func (si SliceIndex) Key() int { + if si.xkey != si.ykey { + return -1 + } + return si.xkey +} + +// SplitKeys are the indexes for indexing into slices in the +// x and y values, respectively. These indexes may differ due to the +// insertion or removal of an element in one of the slices, causing +// all of the indexes to be shifted. If an index is -1, then that +// indicates that the element does not exist in the associated slice. +// +// Key is guaranteed to return -1 if and only if the indexes returned +// by SplitKeys are not the same. SplitKeys will never return -1 for +// both indexes. +func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } + +// MapIndex is an index operation on a map at some index Key. +type MapIndex struct{ *mapIndex } +type mapIndex struct { + pathStep + key reflect.Value +} + +func (mi MapIndex) Type() reflect.Type { return mi.typ } +func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy } +func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) } + +// Key is the value of the map key. +func (mi MapIndex) Key() reflect.Value { return mi.key } + +// Indirect represents pointer indirection on the parent type. +type Indirect struct{ *indirect } +type indirect struct { + pathStep +} + +func (in Indirect) Type() reflect.Type { return in.typ } +func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } +func (in Indirect) String() string { return "*" } + +// TypeAssertion represents a type assertion on an interface. +type TypeAssertion struct{ *typeAssertion } +type typeAssertion struct { + pathStep +} + +func (ta TypeAssertion) Type() reflect.Type { return ta.typ } +func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } +func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) } + +// Transform is a transformation from the parent type to the current type. +type Transform struct{ *transform } +type transform struct { + pathStep + trans *transformer +} + +func (tf Transform) Type() reflect.Type { return tf.typ } +func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } +func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } + +// Name is the name of the Transformer. +func (tf Transform) Name() string { return tf.trans.name } + +// Func is the function pointer to the transformer function. +func (tf Transform) Func() reflect.Value { return tf.trans.fnc } + +// Option returns the originally constructed Transformer option. +// The == operator can be used to detect the exact option used. +func (tf Transform) Option() Option { return tf.trans } + +// pointerPath represents a dual-stack of pointers encountered when +// recursively traversing the x and y values. This data structure supports +// detection of cycles and determining whether the cycles are equal. +// In Go, cycles can occur via pointers, slices, and maps. +// +// The pointerPath uses a map to represent a stack; where descension into a +// pointer pushes the address onto the stack, and ascension from a pointer +// pops the address from the stack. Thus, when traversing into a pointer from +// reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles +// by checking whether the pointer has already been visited. The cycle detection +// uses a seperate stack for the x and y values. +// +// If a cycle is detected we need to determine whether the two pointers +// should be considered equal. The definition of equality chosen by Equal +// requires two graphs to have the same structure. To determine this, both the +// x and y values must have a cycle where the previous pointers were also +// encountered together as a pair. +// +// Semantically, this is equivalent to augmenting Indirect, SliceIndex, and +// MapIndex with pointer information for the x and y values. +// Suppose px and py are two pointers to compare, we then search the +// Path for whether px was ever encountered in the Path history of x, and +// similarly so with py. If either side has a cycle, the comparison is only +// equal if both px and py have a cycle resulting from the same PathStep. +// +// Using a map as a stack is more performant as we can perform cycle detection +// in O(1) instead of O(N) where N is len(Path). +type pointerPath struct { + // mx is keyed by x pointers, where the value is the associated y pointer. + mx map[value.Pointer]value.Pointer + // my is keyed by y pointers, where the value is the associated x pointer. + my map[value.Pointer]value.Pointer +} + +func (p *pointerPath) Init() { + p.mx = make(map[value.Pointer]value.Pointer) + p.my = make(map[value.Pointer]value.Pointer) +} + +// Push indicates intent to descend into pointers vx and vy where +// visited reports whether either has been seen before. If visited before, +// equal reports whether both pointers were encountered together. +// Pop must be called if and only if the pointers were never visited. +// +// The pointers vx and vy must be a reflect.Ptr, reflect.Slice, or reflect.Map +// and be non-nil. +func (p pointerPath) Push(vx, vy reflect.Value) (equal, visited bool) { + px := value.PointerOf(vx) + py := value.PointerOf(vy) + _, ok1 := p.mx[px] + _, ok2 := p.my[py] + if ok1 || ok2 { + equal = p.mx[px] == py && p.my[py] == px // Pointers paired together + return equal, true + } + p.mx[px] = py + p.my[py] = px + return false, false +} + +// Pop ascends from pointers vx and vy. +func (p pointerPath) Pop(vx, vy reflect.Value) { + delete(p.mx, value.PointerOf(vx)) + delete(p.my, value.PointerOf(vy)) +} + +// isExported reports whether the identifier is exported. +func isExported(id string) bool { + r, _ := utf8.DecodeRuneInString(id) + return unicode.IsUpper(r) +} diff --git a/vendor/github.com/google/go-cmp/cmp/report.go b/vendor/github.com/google/go-cmp/cmp/report.go new file mode 100644 index 00000000..aafcb363 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report.go @@ -0,0 +1,54 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +// defaultReporter implements the reporter interface. +// +// As Equal serially calls the PushStep, Report, and PopStep methods, the +// defaultReporter constructs a tree-based representation of the compared value +// and the result of each comparison (see valueNode). +// +// When the String method is called, the FormatDiff method transforms the +// valueNode tree into a textNode tree, which is a tree-based representation +// of the textual output (see textNode). +// +// Lastly, the textNode.String method produces the final report as a string. +type defaultReporter struct { + root *valueNode + curr *valueNode +} + +func (r *defaultReporter) PushStep(ps PathStep) { + r.curr = r.curr.PushStep(ps) + if r.root == nil { + r.root = r.curr + } +} +func (r *defaultReporter) Report(rs Result) { + r.curr.Report(rs) +} +func (r *defaultReporter) PopStep() { + r.curr = r.curr.PopStep() +} + +// String provides a full report of the differences detected as a structured +// literal in pseudo-Go syntax. String may only be called after the entire tree +// has been traversed. +func (r *defaultReporter) String() string { + assert(r.root != nil && r.curr == nil) + if r.root.NumDiff == 0 { + return "" + } + ptrs := new(pointerReferences) + text := formatOptions{}.FormatDiff(r.root, ptrs) + resolveReferences(text) + return text.String() +} + +func assert(ok bool) { + if !ok { + panic("assertion failure") + } +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go new file mode 100644 index 00000000..9e218096 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_compare.go @@ -0,0 +1,432 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import ( + "fmt" + "reflect" + + "github.com/google/go-cmp/cmp/internal/value" +) + +// numContextRecords is the number of surrounding equal records to print. +const numContextRecords = 2 + +type diffMode byte + +const ( + diffUnknown diffMode = 0 + diffIdentical diffMode = ' ' + diffRemoved diffMode = '-' + diffInserted diffMode = '+' +) + +type typeMode int + +const ( + // emitType always prints the type. + emitType typeMode = iota + // elideType never prints the type. + elideType + // autoType prints the type only for composite kinds + // (i.e., structs, slices, arrays, and maps). + autoType +) + +type formatOptions struct { + // DiffMode controls the output mode of FormatDiff. + // + // If diffUnknown, then produce a diff of the x and y values. + // If diffIdentical, then emit values as if they were equal. + // If diffRemoved, then only emit x values (ignoring y values). + // If diffInserted, then only emit y values (ignoring x values). + DiffMode diffMode + + // TypeMode controls whether to print the type for the current node. + // + // As a general rule of thumb, we always print the type of the next node + // after an interface, and always elide the type of the next node after + // a slice or map node. + TypeMode typeMode + + // formatValueOptions are options specific to printing reflect.Values. + formatValueOptions +} + +func (opts formatOptions) WithDiffMode(d diffMode) formatOptions { + opts.DiffMode = d + return opts +} +func (opts formatOptions) WithTypeMode(t typeMode) formatOptions { + opts.TypeMode = t + return opts +} +func (opts formatOptions) WithVerbosity(level int) formatOptions { + opts.VerbosityLevel = level + opts.LimitVerbosity = true + return opts +} +func (opts formatOptions) verbosity() uint { + switch { + case opts.VerbosityLevel < 0: + return 0 + case opts.VerbosityLevel > 16: + return 16 // some reasonable maximum to avoid shift overflow + default: + return uint(opts.VerbosityLevel) + } +} + +const maxVerbosityPreset = 3 + +// verbosityPreset modifies the verbosity settings given an index +// between 0 and maxVerbosityPreset, inclusive. +func verbosityPreset(opts formatOptions, i int) formatOptions { + opts.VerbosityLevel = int(opts.verbosity()) + 2*i + if i > 0 { + opts.AvoidStringer = true + } + if i >= maxVerbosityPreset { + opts.PrintAddresses = true + opts.QualifiedNames = true + } + return opts +} + +// FormatDiff converts a valueNode tree into a textNode tree, where the later +// is a textual representation of the differences detected in the former. +func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) { + if opts.DiffMode == diffIdentical { + opts = opts.WithVerbosity(1) + } else { + opts = opts.WithVerbosity(3) + } + + // Check whether we have specialized formatting for this node. + // This is not necessary, but helpful for producing more readable outputs. + if opts.CanFormatDiffSlice(v) { + return opts.FormatDiffSlice(v) + } + + var parentKind reflect.Kind + if v.parent != nil && v.parent.TransformerName == "" { + parentKind = v.parent.Type.Kind() + } + + // For leaf nodes, format the value based on the reflect.Values alone. + if v.MaxDepth == 0 { + switch opts.DiffMode { + case diffUnknown, diffIdentical: + // Format Equal. + if v.NumDiff == 0 { + outx := opts.FormatValue(v.ValueX, parentKind, ptrs) + outy := opts.FormatValue(v.ValueY, parentKind, ptrs) + if v.NumIgnored > 0 && v.NumSame == 0 { + return textEllipsis + } else if outx.Len() < outy.Len() { + return outx + } else { + return outy + } + } + + // Format unequal. + assert(opts.DiffMode == diffUnknown) + var list textList + outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs) + outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, parentKind, ptrs) + for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { + opts2 := verbosityPreset(opts, i).WithTypeMode(elideType) + outx = opts2.FormatValue(v.ValueX, parentKind, ptrs) + outy = opts2.FormatValue(v.ValueY, parentKind, ptrs) + } + if outx != nil { + list = append(list, textRecord{Diff: '-', Value: outx}) + } + if outy != nil { + list = append(list, textRecord{Diff: '+', Value: outy}) + } + return opts.WithTypeMode(emitType).FormatType(v.Type, list) + case diffRemoved: + return opts.FormatValue(v.ValueX, parentKind, ptrs) + case diffInserted: + return opts.FormatValue(v.ValueY, parentKind, ptrs) + default: + panic("invalid diff mode") + } + } + + // Register slice element to support cycle detection. + if parentKind == reflect.Slice { + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, true) + defer ptrs.Pop() + defer func() { out = wrapTrunkReferences(ptrRefs, out) }() + } + + // Descend into the child value node. + if v.TransformerName != "" { + out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) + out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"} + return opts.FormatType(v.Type, out) + } else { + switch k := v.Type.Kind(); k { + case reflect.Struct, reflect.Array, reflect.Slice: + out = opts.formatDiffList(v.Records, k, ptrs) + out = opts.FormatType(v.Type, out) + case reflect.Map: + // Register map to support cycle detection. + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) + defer ptrs.Pop() + + out = opts.formatDiffList(v.Records, k, ptrs) + out = wrapTrunkReferences(ptrRefs, out) + out = opts.FormatType(v.Type, out) + case reflect.Ptr: + // Register pointer to support cycle detection. + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) + defer ptrs.Pop() + + out = opts.FormatDiff(v.Value, ptrs) + out = wrapTrunkReferences(ptrRefs, out) + out = &textWrap{Prefix: "&", Value: out} + case reflect.Interface: + out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) + default: + panic(fmt.Sprintf("%v cannot have children", k)) + } + return out + } +} + +func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode { + // Derive record name based on the data structure kind. + var name string + var formatKey func(reflect.Value) string + switch k { + case reflect.Struct: + name = "field" + opts = opts.WithTypeMode(autoType) + formatKey = func(v reflect.Value) string { return v.String() } + case reflect.Slice, reflect.Array: + name = "element" + opts = opts.WithTypeMode(elideType) + formatKey = func(reflect.Value) string { return "" } + case reflect.Map: + name = "entry" + opts = opts.WithTypeMode(elideType) + formatKey = func(v reflect.Value) string { return formatMapKey(v, false, ptrs) } + } + + maxLen := -1 + if opts.LimitVerbosity { + if opts.DiffMode == diffIdentical { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + } else { + maxLen = (1 << opts.verbosity()) << 1 // 2, 4, 8, 16, 32, 64, etc... + } + opts.VerbosityLevel-- + } + + // Handle unification. + switch opts.DiffMode { + case diffIdentical, diffRemoved, diffInserted: + var list textList + var deferredEllipsis bool // Add final "..." to indicate records were dropped + for _, r := range recs { + if len(list) == maxLen { + deferredEllipsis = true + break + } + + // Elide struct fields that are zero value. + if k == reflect.Struct { + var isZero bool + switch opts.DiffMode { + case diffIdentical: + isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY) + case diffRemoved: + isZero = value.IsZero(r.Value.ValueX) + case diffInserted: + isZero = value.IsZero(r.Value.ValueY) + } + if isZero { + continue + } + } + // Elide ignored nodes. + if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 { + deferredEllipsis = !(k == reflect.Slice || k == reflect.Array) + if !deferredEllipsis { + list.AppendEllipsis(diffStats{}) + } + continue + } + if out := opts.FormatDiff(r.Value, ptrs); out != nil { + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + } + } + if deferredEllipsis { + list.AppendEllipsis(diffStats{}) + } + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} + case diffUnknown: + default: + panic("invalid diff mode") + } + + // Handle differencing. + var numDiffs int + var list textList + var keys []reflect.Value // invariant: len(list) == len(keys) + groups := coalesceAdjacentRecords(name, recs) + maxGroup := diffStats{Name: name} + for i, ds := range groups { + if maxLen >= 0 && numDiffs >= maxLen { + maxGroup = maxGroup.Append(ds) + continue + } + + // Handle equal records. + if ds.NumDiff() == 0 { + // Compute the number of leading and trailing records to print. + var numLo, numHi int + numEqual := ds.NumIgnored + ds.NumIdentical + for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 { + if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { + break + } + numLo++ + } + for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { + if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { + break + } + numHi++ + } + if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 { + numHi++ // Avoid pointless coalescing of a single equal record + } + + // Format the equal values. + for _, r := range recs[:numLo] { + out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + } + if numEqual > numLo+numHi { + ds.NumIdentical -= numLo + numHi + list.AppendEllipsis(ds) + for len(keys) < len(list) { + keys = append(keys, reflect.Value{}) + } + } + for _, r := range recs[numEqual-numHi : numEqual] { + out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + } + recs = recs[numEqual:] + continue + } + + // Handle unequal records. + for _, r := range recs[:ds.NumDiff()] { + switch { + case opts.CanFormatDiffSlice(r.Value): + out := opts.FormatDiffSlice(r.Value) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + case r.Value.NumChildren == r.Value.MaxDepth: + outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) + outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) + for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { + opts2 := verbosityPreset(opts, i) + outx = opts2.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) + outy = opts2.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) + } + if outx != nil { + list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx}) + keys = append(keys, r.Key) + } + if outy != nil { + list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy}) + keys = append(keys, r.Key) + } + default: + out := opts.FormatDiff(r.Value, ptrs) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + } + } + recs = recs[ds.NumDiff():] + numDiffs += ds.NumDiff() + } + if maxGroup.IsZero() { + assert(len(recs) == 0) + } else { + list.AppendEllipsis(maxGroup) + for len(keys) < len(list) { + keys = append(keys, reflect.Value{}) + } + } + assert(len(list) == len(keys)) + + // For maps, the default formatting logic uses fmt.Stringer which may + // produce ambiguous output. Avoid calling String to disambiguate. + if k == reflect.Map { + var ambiguous bool + seenKeys := map[string]reflect.Value{} + for i, currKey := range keys { + if currKey.IsValid() { + strKey := list[i].Key + prevKey, seen := seenKeys[strKey] + if seen && prevKey.CanInterface() && currKey.CanInterface() { + ambiguous = prevKey.Interface() != currKey.Interface() + if ambiguous { + break + } + } + seenKeys[strKey] = currKey + } + } + if ambiguous { + for i, k := range keys { + if k.IsValid() { + list[i].Key = formatMapKey(k, true, ptrs) + } + } + } + } + + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} +} + +// coalesceAdjacentRecords coalesces the list of records into groups of +// adjacent equal, or unequal counts. +func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) { + var prevCase int // Arbitrary index into which case last occurred + lastStats := func(i int) *diffStats { + if prevCase != i { + groups = append(groups, diffStats{Name: name}) + prevCase = i + } + return &groups[len(groups)-1] + } + for _, r := range recs { + switch rv := r.Value; { + case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0: + lastStats(1).NumIgnored++ + case rv.NumDiff == 0: + lastStats(1).NumIdentical++ + case rv.NumDiff > 0 && !rv.ValueY.IsValid(): + lastStats(2).NumRemoved++ + case rv.NumDiff > 0 && !rv.ValueX.IsValid(): + lastStats(2).NumInserted++ + default: + lastStats(2).NumModified++ + } + } + return groups +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_references.go b/vendor/github.com/google/go-cmp/cmp/report_references.go new file mode 100644 index 00000000..d620c2c2 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_references.go @@ -0,0 +1,264 @@ +// Copyright 2020, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp/internal/flags" + "github.com/google/go-cmp/cmp/internal/value" +) + +const ( + pointerDelimPrefix = "⟪" + pointerDelimSuffix = "⟫" +) + +// formatPointer prints the address of the pointer. +func formatPointer(p value.Pointer, withDelims bool) string { + v := p.Uintptr() + if flags.Deterministic { + v = 0xdeadf00f // Only used for stable testing purposes + } + if withDelims { + return pointerDelimPrefix + formatHex(uint64(v)) + pointerDelimSuffix + } + return formatHex(uint64(v)) +} + +// pointerReferences is a stack of pointers visited so far. +type pointerReferences [][2]value.Pointer + +func (ps *pointerReferences) PushPair(vx, vy reflect.Value, d diffMode, deref bool) (pp [2]value.Pointer) { + if deref && vx.IsValid() { + vx = vx.Addr() + } + if deref && vy.IsValid() { + vy = vy.Addr() + } + switch d { + case diffUnknown, diffIdentical: + pp = [2]value.Pointer{value.PointerOf(vx), value.PointerOf(vy)} + case diffRemoved: + pp = [2]value.Pointer{value.PointerOf(vx), value.Pointer{}} + case diffInserted: + pp = [2]value.Pointer{value.Pointer{}, value.PointerOf(vy)} + } + *ps = append(*ps, pp) + return pp +} + +func (ps *pointerReferences) Push(v reflect.Value) (p value.Pointer, seen bool) { + p = value.PointerOf(v) + for _, pp := range *ps { + if p == pp[0] || p == pp[1] { + return p, true + } + } + *ps = append(*ps, [2]value.Pointer{p, p}) + return p, false +} + +func (ps *pointerReferences) Pop() { + *ps = (*ps)[:len(*ps)-1] +} + +// trunkReferences is metadata for a textNode indicating that the sub-tree +// represents the value for either pointer in a pair of references. +type trunkReferences struct{ pp [2]value.Pointer } + +// trunkReference is metadata for a textNode indicating that the sub-tree +// represents the value for the given pointer reference. +type trunkReference struct{ p value.Pointer } + +// leafReference is metadata for a textNode indicating that the value is +// truncated as it refers to another part of the tree (i.e., a trunk). +type leafReference struct{ p value.Pointer } + +func wrapTrunkReferences(pp [2]value.Pointer, s textNode) textNode { + switch { + case pp[0].IsNil(): + return &textWrap{Value: s, Metadata: trunkReference{pp[1]}} + case pp[1].IsNil(): + return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} + case pp[0] == pp[1]: + return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} + default: + return &textWrap{Value: s, Metadata: trunkReferences{pp}} + } +} +func wrapTrunkReference(p value.Pointer, printAddress bool, s textNode) textNode { + var prefix string + if printAddress { + prefix = formatPointer(p, true) + } + return &textWrap{Prefix: prefix, Value: s, Metadata: trunkReference{p}} +} +func makeLeafReference(p value.Pointer, printAddress bool) textNode { + out := &textWrap{Prefix: "(", Value: textEllipsis, Suffix: ")"} + var prefix string + if printAddress { + prefix = formatPointer(p, true) + } + return &textWrap{Prefix: prefix, Value: out, Metadata: leafReference{p}} +} + +// resolveReferences walks the textNode tree searching for any leaf reference +// metadata and resolves each against the corresponding trunk references. +// Since pointer addresses in memory are not particularly readable to the user, +// it replaces each pointer value with an arbitrary and unique reference ID. +func resolveReferences(s textNode) { + var walkNodes func(textNode, func(textNode)) + walkNodes = func(s textNode, f func(textNode)) { + f(s) + switch s := s.(type) { + case *textWrap: + walkNodes(s.Value, f) + case textList: + for _, r := range s { + walkNodes(r.Value, f) + } + } + } + + // Collect all trunks and leaves with reference metadata. + var trunks, leaves []*textWrap + walkNodes(s, func(s textNode) { + if s, ok := s.(*textWrap); ok { + switch s.Metadata.(type) { + case leafReference: + leaves = append(leaves, s) + case trunkReference, trunkReferences: + trunks = append(trunks, s) + } + } + }) + + // No leaf references to resolve. + if len(leaves) == 0 { + return + } + + // Collect the set of all leaf references to resolve. + leafPtrs := make(map[value.Pointer]bool) + for _, leaf := range leaves { + leafPtrs[leaf.Metadata.(leafReference).p] = true + } + + // Collect the set of trunk pointers that are always paired together. + // This allows us to assign a single ID to both pointers for brevity. + // If a pointer in a pair ever occurs by itself or as a different pair, + // then the pair is broken. + pairedTrunkPtrs := make(map[value.Pointer]value.Pointer) + unpair := func(p value.Pointer) { + if !pairedTrunkPtrs[p].IsNil() { + pairedTrunkPtrs[pairedTrunkPtrs[p]] = value.Pointer{} // invalidate other half + } + pairedTrunkPtrs[p] = value.Pointer{} // invalidate this half + } + for _, trunk := range trunks { + switch p := trunk.Metadata.(type) { + case trunkReference: + unpair(p.p) // standalone pointer cannot be part of a pair + case trunkReferences: + p0, ok0 := pairedTrunkPtrs[p.pp[0]] + p1, ok1 := pairedTrunkPtrs[p.pp[1]] + switch { + case !ok0 && !ok1: + // Register the newly seen pair. + pairedTrunkPtrs[p.pp[0]] = p.pp[1] + pairedTrunkPtrs[p.pp[1]] = p.pp[0] + case ok0 && ok1 && p0 == p.pp[1] && p1 == p.pp[0]: + // Exact pair already seen; do nothing. + default: + // Pair conflicts with some other pair; break all pairs. + unpair(p.pp[0]) + unpair(p.pp[1]) + } + } + } + + // Correlate each pointer referenced by leaves to a unique identifier, + // and print the IDs for each trunk that matches those pointers. + var nextID uint + ptrIDs := make(map[value.Pointer]uint) + newID := func() uint { + id := nextID + nextID++ + return id + } + for _, trunk := range trunks { + switch p := trunk.Metadata.(type) { + case trunkReference: + if print := leafPtrs[p.p]; print { + id, ok := ptrIDs[p.p] + if !ok { + id = newID() + ptrIDs[p.p] = id + } + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) + } + case trunkReferences: + print0 := leafPtrs[p.pp[0]] + print1 := leafPtrs[p.pp[1]] + if print0 || print1 { + id0, ok0 := ptrIDs[p.pp[0]] + id1, ok1 := ptrIDs[p.pp[1]] + isPair := pairedTrunkPtrs[p.pp[0]] == p.pp[1] && pairedTrunkPtrs[p.pp[1]] == p.pp[0] + if isPair { + var id uint + assert(ok0 == ok1) // must be seen together or not at all + if ok0 { + assert(id0 == id1) // must have the same ID + id = id0 + } else { + id = newID() + ptrIDs[p.pp[0]] = id + ptrIDs[p.pp[1]] = id + } + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) + } else { + if print0 && !ok0 { + id0 = newID() + ptrIDs[p.pp[0]] = id0 + } + if print1 && !ok1 { + id1 = newID() + ptrIDs[p.pp[1]] = id1 + } + switch { + case print0 && print1: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)+","+formatReference(id1)) + case print0: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)) + case print1: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id1)) + } + } + } + } + } + + // Update all leaf references with the unique identifier. + for _, leaf := range leaves { + if id, ok := ptrIDs[leaf.Metadata.(leafReference).p]; ok { + leaf.Prefix = updateReferencePrefix(leaf.Prefix, formatReference(id)) + } + } +} + +func formatReference(id uint) string { + return fmt.Sprintf("ref#%d", id) +} + +func updateReferencePrefix(prefix, ref string) string { + if prefix == "" { + return pointerDelimPrefix + ref + pointerDelimSuffix + } + suffix := strings.TrimPrefix(prefix, pointerDelimPrefix) + return pointerDelimPrefix + ref + ": " + suffix +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go new file mode 100644 index 00000000..2d722ea5 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_reflect.go @@ -0,0 +1,353 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/value" +) + +type formatValueOptions struct { + // AvoidStringer controls whether to avoid calling custom stringer + // methods like error.Error or fmt.Stringer.String. + AvoidStringer bool + + // PrintAddresses controls whether to print the address of all pointers, + // slice elements, and maps. + PrintAddresses bool + + // QualifiedNames controls whether FormatType uses the fully qualified name + // (including the full package path as opposed to just the package name). + QualifiedNames bool + + // VerbosityLevel controls the amount of output to produce. + // A higher value produces more output. A value of zero or lower produces + // no output (represented using an ellipsis). + // If LimitVerbosity is false, then the level is treated as infinite. + VerbosityLevel int + + // LimitVerbosity specifies that formatting should respect VerbosityLevel. + LimitVerbosity bool +} + +// FormatType prints the type as if it were wrapping s. +// This may return s as-is depending on the current type and TypeMode mode. +func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode { + // Check whether to emit the type or not. + switch opts.TypeMode { + case autoType: + switch t.Kind() { + case reflect.Struct, reflect.Slice, reflect.Array, reflect.Map: + if s.Equal(textNil) { + return s + } + default: + return s + } + if opts.DiffMode == diffIdentical { + return s // elide type for identical nodes + } + case elideType: + return s + } + + // Determine the type label, applying special handling for unnamed types. + typeName := value.TypeString(t, opts.QualifiedNames) + if t.Name() == "" { + // According to Go grammar, certain type literals contain symbols that + // do not strongly bind to the next lexicographical token (e.g., *T). + switch t.Kind() { + case reflect.Chan, reflect.Func, reflect.Ptr: + typeName = "(" + typeName + ")" + } + } + return &textWrap{Prefix: typeName, Value: wrapParens(s)} +} + +// wrapParens wraps s with a set of parenthesis, but avoids it if the +// wrapped node itself is already surrounded by a pair of parenthesis or braces. +// It handles unwrapping one level of pointer-reference nodes. +func wrapParens(s textNode) textNode { + var refNode *textWrap + if s2, ok := s.(*textWrap); ok { + // Unwrap a single pointer reference node. + switch s2.Metadata.(type) { + case leafReference, trunkReference, trunkReferences: + refNode = s2 + if s3, ok := refNode.Value.(*textWrap); ok { + s2 = s3 + } + } + + // Already has delimiters that make parenthesis unnecessary. + hasParens := strings.HasPrefix(s2.Prefix, "(") && strings.HasSuffix(s2.Suffix, ")") + hasBraces := strings.HasPrefix(s2.Prefix, "{") && strings.HasSuffix(s2.Suffix, "}") + if hasParens || hasBraces { + return s + } + } + if refNode != nil { + refNode.Value = &textWrap{Prefix: "(", Value: refNode.Value, Suffix: ")"} + return s + } + return &textWrap{Prefix: "(", Value: s, Suffix: ")"} +} + +// FormatValue prints the reflect.Value, taking extra care to avoid descending +// into pointers already in ptrs. As pointers are visited, ptrs is also updated. +func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, ptrs *pointerReferences) (out textNode) { + if !v.IsValid() { + return nil + } + t := v.Type() + + // Check slice element for cycles. + if parentKind == reflect.Slice { + ptrRef, visited := ptrs.Push(v.Addr()) + if visited { + return makeLeafReference(ptrRef, false) + } + defer ptrs.Pop() + defer func() { out = wrapTrunkReference(ptrRef, false, out) }() + } + + // Check whether there is an Error or String method to call. + if !opts.AvoidStringer && v.CanInterface() { + // Avoid calling Error or String methods on nil receivers since many + // implementations crash when doing so. + if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() { + var prefix, strVal string + switch v := v.Interface().(type) { + case error: + prefix, strVal = "e", v.Error() + case fmt.Stringer: + prefix, strVal = "s", v.String() + } + if prefix != "" { + maxLen := len(strVal) + if opts.LimitVerbosity { + maxLen = (1 << opts.verbosity()) << 5 // 32, 64, 128, 256, etc... + } + if len(strVal) > maxLen+len(textEllipsis) { + return textLine(prefix + formatString(strVal[:maxLen]) + string(textEllipsis)) + } + return textLine(prefix + formatString(strVal)) + } + } + } + + // Check whether to explicitly wrap the result with the type. + var skipType bool + defer func() { + if !skipType { + out = opts.FormatType(t, out) + } + }() + + switch t.Kind() { + case reflect.Bool: + return textLine(fmt.Sprint(v.Bool())) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return textLine(fmt.Sprint(v.Int())) + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return textLine(fmt.Sprint(v.Uint())) + case reflect.Uint8: + if parentKind == reflect.Slice || parentKind == reflect.Array { + return textLine(formatHex(v.Uint())) + } + return textLine(fmt.Sprint(v.Uint())) + case reflect.Uintptr: + return textLine(formatHex(v.Uint())) + case reflect.Float32, reflect.Float64: + return textLine(fmt.Sprint(v.Float())) + case reflect.Complex64, reflect.Complex128: + return textLine(fmt.Sprint(v.Complex())) + case reflect.String: + maxLen := v.Len() + if opts.LimitVerbosity { + maxLen = (1 << opts.verbosity()) << 5 // 32, 64, 128, 256, etc... + } + if v.Len() > maxLen+len(textEllipsis) { + return textLine(formatString(v.String()[:maxLen]) + string(textEllipsis)) + } + return textLine(formatString(v.String())) + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + return textLine(formatPointer(value.PointerOf(v), true)) + case reflect.Struct: + var list textList + v := makeAddressable(v) // needed for retrieveUnexportedField + maxLen := v.NumField() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } + for i := 0; i < v.NumField(); i++ { + vv := v.Field(i) + if value.IsZero(vv) { + continue // Elide fields with zero values + } + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + sf := t.Field(i) + if supportExporters && !isExported(sf.Name) { + vv = retrieveUnexportedField(v, sf, true) + } + s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs) + list = append(list, textRecord{Key: sf.Name, Value: s}) + } + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} + case reflect.Slice: + if v.IsNil() { + return textNil + } + fallthrough + case reflect.Array: + maxLen := v.Len() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } + var list textList + for i := 0; i < v.Len(); i++ { + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + s := opts.WithTypeMode(elideType).FormatValue(v.Index(i), t.Kind(), ptrs) + list = append(list, textRecord{Value: s}) + } + + out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + if t.Kind() == reflect.Slice && opts.PrintAddresses { + header := fmt.Sprintf("ptr:%v, len:%d, cap:%d", formatPointer(value.PointerOf(v), false), v.Len(), v.Cap()) + out = &textWrap{Prefix: pointerDelimPrefix + header + pointerDelimSuffix, Value: out} + } + return out + case reflect.Map: + if v.IsNil() { + return textNil + } + + // Check pointer for cycles. + ptrRef, visited := ptrs.Push(v) + if visited { + return makeLeafReference(ptrRef, opts.PrintAddresses) + } + defer ptrs.Pop() + + maxLen := v.Len() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } + var list textList + for _, k := range value.SortKeys(v.MapKeys()) { + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + sk := formatMapKey(k, false, ptrs) + sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), t.Kind(), ptrs) + list = append(list, textRecord{Key: sk, Value: sv}) + } + + out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) + return out + case reflect.Ptr: + if v.IsNil() { + return textNil + } + + // Check pointer for cycles. + ptrRef, visited := ptrs.Push(v) + if visited { + out = makeLeafReference(ptrRef, opts.PrintAddresses) + return &textWrap{Prefix: "&", Value: out} + } + defer ptrs.Pop() + + skipType = true // Let the underlying value print the type instead + out = opts.FormatValue(v.Elem(), t.Kind(), ptrs) + out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) + out = &textWrap{Prefix: "&", Value: out} + return out + case reflect.Interface: + if v.IsNil() { + return textNil + } + // Interfaces accept different concrete types, + // so configure the underlying value to explicitly print the type. + skipType = true // Print the concrete type instead + return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs) + default: + panic(fmt.Sprintf("%v kind not handled", v.Kind())) + } +} + +// formatMapKey formats v as if it were a map key. +// The result is guaranteed to be a single line. +func formatMapKey(v reflect.Value, disambiguate bool, ptrs *pointerReferences) string { + var opts formatOptions + opts.DiffMode = diffIdentical + opts.TypeMode = elideType + opts.PrintAddresses = disambiguate + opts.AvoidStringer = disambiguate + opts.QualifiedNames = disambiguate + s := opts.FormatValue(v, reflect.Map, ptrs).String() + return strings.TrimSpace(s) +} + +// formatString prints s as a double-quoted or backtick-quoted string. +func formatString(s string) string { + // Use quoted string if it the same length as a raw string literal. + // Otherwise, attempt to use the raw string form. + qs := strconv.Quote(s) + if len(qs) == 1+len(s)+1 { + return qs + } + + // Disallow newlines to ensure output is a single line. + // Only allow printable runes for readability purposes. + rawInvalid := func(r rune) bool { + return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t') + } + if utf8.ValidString(s) && strings.IndexFunc(s, rawInvalid) < 0 { + return "`" + s + "`" + } + return qs +} + +// formatHex prints u as a hexadecimal integer in Go notation. +func formatHex(u uint64) string { + var f string + switch { + case u <= 0xff: + f = "0x%02x" + case u <= 0xffff: + f = "0x%04x" + case u <= 0xffffff: + f = "0x%06x" + case u <= 0xffffffff: + f = "0x%08x" + case u <= 0xffffffffff: + f = "0x%010x" + case u <= 0xffffffffffff: + f = "0x%012x" + case u <= 0xffffffffffffff: + f = "0x%014x" + case u <= 0xffffffffffffffff: + f = "0x%016x" + } + return fmt.Sprintf(f, u) +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go new file mode 100644 index 00000000..35315dad --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_slices.go @@ -0,0 +1,448 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/diff" +) + +// CanFormatDiffSlice reports whether we support custom formatting for nodes +// that are slices of primitive kinds or strings. +func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { + switch { + case opts.DiffMode != diffUnknown: + return false // Must be formatting in diff mode + case v.NumDiff == 0: + return false // No differences detected + case !v.ValueX.IsValid() || !v.ValueY.IsValid(): + return false // Both values must be valid + case v.Type.Kind() == reflect.Slice && (v.ValueX.Len() == 0 || v.ValueY.Len() == 0): + return false // Both slice values have to be non-empty + case v.NumIgnored > 0: + return false // Some ignore option was used + case v.NumTransformed > 0: + return false // Some transform option was used + case v.NumCompared > 1: + return false // More than one comparison was used + case v.NumCompared == 1 && v.Type.Name() != "": + // The need for cmp to check applicability of options on every element + // in a slice is a significant performance detriment for large []byte. + // The workaround is to specify Comparer(bytes.Equal), + // which enables cmp to compare []byte more efficiently. + // If they differ, we still want to provide batched diffing. + // The logic disallows named types since they tend to have their own + // String method, with nicer formatting than what this provides. + return false + } + + switch t := v.Type; t.Kind() { + case reflect.String: + case reflect.Array, reflect.Slice: + // Only slices of primitive types have specialized handling. + switch t.Elem().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + default: + return false + } + + // If a sufficient number of elements already differ, + // use specialized formatting even if length requirement is not met. + if v.NumDiff > v.NumSame { + return true + } + default: + return false + } + + // Use specialized string diffing for longer slices or strings. + const minLength = 64 + return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength +} + +// FormatDiffSlice prints a diff for the slices (or strings) represented by v. +// This provides custom-tailored logic to make printing of differences in +// textual strings and slices of primitive kinds more readable. +func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { + assert(opts.DiffMode == diffUnknown) + t, vx, vy := v.Type, v.ValueX, v.ValueY + + // Auto-detect the type of the data. + var isLinedText, isText, isBinary bool + var sx, sy string + switch { + case t.Kind() == reflect.String: + sx, sy = vx.String(), vy.String() + isText = true // Initial estimate, verify later + case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)): + sx, sy = string(vx.Bytes()), string(vy.Bytes()) + isBinary = true // Initial estimate, verify later + case t.Kind() == reflect.Array: + // Arrays need to be addressable for slice operations to work. + vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem() + vx2.Set(vx) + vy2.Set(vy) + vx, vy = vx2, vy2 + } + if isText || isBinary { + var numLines, lastLineIdx, maxLineLen int + isBinary = !utf8.ValidString(sx) || !utf8.ValidString(sy) + for i, r := range sx + sy { + if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError { + isBinary = true + break + } + if r == '\n' { + if maxLineLen < i-lastLineIdx { + maxLineLen = i - lastLineIdx + } + lastLineIdx = i + 1 + numLines++ + } + } + isText = !isBinary + isLinedText = isText && numLines >= 4 && maxLineLen <= 1024 + } + + // Format the string into printable records. + var list textList + var delim string + switch { + // If the text appears to be multi-lined text, + // then perform differencing across individual lines. + case isLinedText: + ssx := strings.Split(sx, "\n") + ssy := strings.Split(sy, "\n") + list = opts.formatDiffSlice( + reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line", + func(v reflect.Value, d diffMode) textRecord { + s := formatString(v.Index(0).String()) + return textRecord{Diff: d, Value: textLine(s)} + }, + ) + delim = "\n" + + // If possible, use a custom triple-quote (""") syntax for printing + // differences in a string literal. This format is more readable, + // but has edge-cases where differences are visually indistinguishable. + // This format is avoided under the following conditions: + // • A line starts with `"""` + // • A line starts with "..." + // • A line contains non-printable characters + // • Adjacent different lines differ only by whitespace + // + // For example: + // """ + // ... // 3 identical lines + // foo + // bar + // - baz + // + BAZ + // """ + isTripleQuoted := true + prevRemoveLines := map[string]bool{} + prevInsertLines := map[string]bool{} + var list2 textList + list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) + for _, r := range list { + if !r.Value.Equal(textEllipsis) { + line, _ := strconv.Unquote(string(r.Value.(textLine))) + line = strings.TrimPrefix(strings.TrimSuffix(line, "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support + normLine := strings.Map(func(r rune) rune { + if unicode.IsSpace(r) { + return -1 // drop whitespace to avoid visually indistinguishable output + } + return r + }, line) + isPrintable := func(r rune) bool { + return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable + } + isTripleQuoted = !strings.HasPrefix(line, `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" + switch r.Diff { + case diffRemoved: + isTripleQuoted = isTripleQuoted && !prevInsertLines[normLine] + prevRemoveLines[normLine] = true + case diffInserted: + isTripleQuoted = isTripleQuoted && !prevRemoveLines[normLine] + prevInsertLines[normLine] = true + } + if !isTripleQuoted { + break + } + r.Value = textLine(line) + r.ElideComma = true + } + if !(r.Diff == diffRemoved || r.Diff == diffInserted) { // start a new non-adjacent difference group + prevRemoveLines = map[string]bool{} + prevInsertLines = map[string]bool{} + } + list2 = append(list2, r) + } + if r := list2[len(list2)-1]; r.Diff == diffIdentical && len(r.Value.(textLine)) == 0 { + list2 = list2[:len(list2)-1] // elide single empty line at the end + } + list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) + if isTripleQuoted { + var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"} + switch t.Kind() { + case reflect.String: + if t != reflect.TypeOf(string("")) { + out = opts.FormatType(t, out) + } + case reflect.Slice: + // Always emit type for slices since the triple-quote syntax + // looks like a string (not a slice). + opts = opts.WithTypeMode(emitType) + out = opts.FormatType(t, out) + } + return out + } + + // If the text appears to be single-lined text, + // then perform differencing in approximately fixed-sized chunks. + // The output is printed as quoted strings. + case isText: + list = opts.formatDiffSlice( + reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte", + func(v reflect.Value, d diffMode) textRecord { + s := formatString(v.String()) + return textRecord{Diff: d, Value: textLine(s)} + }, + ) + delim = "" + + // If the text appears to be binary data, + // then perform differencing in approximately fixed-sized chunks. + // The output is inspired by hexdump. + case isBinary: + list = opts.formatDiffSlice( + reflect.ValueOf(sx), reflect.ValueOf(sy), 16, "byte", + func(v reflect.Value, d diffMode) textRecord { + var ss []string + for i := 0; i < v.Len(); i++ { + ss = append(ss, formatHex(v.Index(i).Uint())) + } + s := strings.Join(ss, ", ") + comment := commentString(fmt.Sprintf("%c|%v|", d, formatASCII(v.String()))) + return textRecord{Diff: d, Value: textLine(s), Comment: comment} + }, + ) + + // For all other slices of primitive types, + // then perform differencing in approximately fixed-sized chunks. + // The size of each chunk depends on the width of the element kind. + default: + var chunkSize int + if t.Elem().Kind() == reflect.Bool { + chunkSize = 16 + } else { + switch t.Elem().Bits() { + case 8: + chunkSize = 16 + case 16: + chunkSize = 12 + case 32: + chunkSize = 8 + default: + chunkSize = 8 + } + } + list = opts.formatDiffSlice( + vx, vy, chunkSize, t.Elem().Kind().String(), + func(v reflect.Value, d diffMode) textRecord { + var ss []string + for i := 0; i < v.Len(); i++ { + switch t.Elem().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + ss = append(ss, fmt.Sprint(v.Index(i).Int())) + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: + ss = append(ss, fmt.Sprint(v.Index(i).Uint())) + case reflect.Uint8, reflect.Uintptr: + ss = append(ss, formatHex(v.Index(i).Uint())) + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + ss = append(ss, fmt.Sprint(v.Index(i).Interface())) + } + } + s := strings.Join(ss, ", ") + return textRecord{Diff: d, Value: textLine(s)} + }, + ) + } + + // Wrap the output with appropriate type information. + var out textNode = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + if !isText { + // The "{...}" byte-sequence literal is not valid Go syntax for strings. + // Emit the type for extra clarity (e.g. "string{...}"). + if t.Kind() == reflect.String { + opts = opts.WithTypeMode(emitType) + } + return opts.FormatType(t, out) + } + switch t.Kind() { + case reflect.String: + out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} + if t != reflect.TypeOf(string("")) { + out = opts.FormatType(t, out) + } + case reflect.Slice: + out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} + if t != reflect.TypeOf([]byte(nil)) { + out = opts.FormatType(t, out) + } + } + return out +} + +// formatASCII formats s as an ASCII string. +// This is useful for printing binary strings in a semi-legible way. +func formatASCII(s string) string { + b := bytes.Repeat([]byte{'.'}, len(s)) + for i := 0; i < len(s); i++ { + if ' ' <= s[i] && s[i] <= '~' { + b[i] = s[i] + } + } + return string(b) +} + +func (opts formatOptions) formatDiffSlice( + vx, vy reflect.Value, chunkSize int, name string, + makeRec func(reflect.Value, diffMode) textRecord, +) (list textList) { + es := diff.Difference(vx.Len(), vy.Len(), func(ix int, iy int) diff.Result { + return diff.BoolResult(vx.Index(ix).Interface() == vy.Index(iy).Interface()) + }) + + appendChunks := func(v reflect.Value, d diffMode) int { + n0 := v.Len() + for v.Len() > 0 { + n := chunkSize + if n > v.Len() { + n = v.Len() + } + list = append(list, makeRec(v.Slice(0, n), d)) + v = v.Slice(n, v.Len()) + } + return n0 - v.Len() + } + + var numDiffs int + maxLen := -1 + if opts.LimitVerbosity { + maxLen = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc... + opts.VerbosityLevel-- + } + + groups := coalesceAdjacentEdits(name, es) + groups = coalesceInterveningIdentical(groups, chunkSize/4) + maxGroup := diffStats{Name: name} + for i, ds := range groups { + if maxLen >= 0 && numDiffs >= maxLen { + maxGroup = maxGroup.Append(ds) + continue + } + + // Print equal. + if ds.NumDiff() == 0 { + // Compute the number of leading and trailing equal bytes to print. + var numLo, numHi int + numEqual := ds.NumIgnored + ds.NumIdentical + for numLo < chunkSize*numContextRecords && numLo+numHi < numEqual && i != 0 { + numLo++ + } + for numHi < chunkSize*numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { + numHi++ + } + if numEqual-(numLo+numHi) <= chunkSize && ds.NumIgnored == 0 { + numHi = numEqual - numLo // Avoid pointless coalescing of single equal row + } + + // Print the equal bytes. + appendChunks(vx.Slice(0, numLo), diffIdentical) + if numEqual > numLo+numHi { + ds.NumIdentical -= numLo + numHi + list.AppendEllipsis(ds) + } + appendChunks(vx.Slice(numEqual-numHi, numEqual), diffIdentical) + vx = vx.Slice(numEqual, vx.Len()) + vy = vy.Slice(numEqual, vy.Len()) + continue + } + + // Print unequal. + len0 := len(list) + nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved) + vx = vx.Slice(nx, vx.Len()) + ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted) + vy = vy.Slice(ny, vy.Len()) + numDiffs += len(list) - len0 + } + if maxGroup.IsZero() { + assert(vx.Len() == 0 && vy.Len() == 0) + } else { + list.AppendEllipsis(maxGroup) + } + return list +} + +// coalesceAdjacentEdits coalesces the list of edits into groups of adjacent +// equal or unequal counts. +func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) { + var prevCase int // Arbitrary index into which case last occurred + lastStats := func(i int) *diffStats { + if prevCase != i { + groups = append(groups, diffStats{Name: name}) + prevCase = i + } + return &groups[len(groups)-1] + } + for _, e := range es { + switch e { + case diff.Identity: + lastStats(1).NumIdentical++ + case diff.UniqueX: + lastStats(2).NumRemoved++ + case diff.UniqueY: + lastStats(2).NumInserted++ + case diff.Modified: + lastStats(2).NumModified++ + } + } + return groups +} + +// coalesceInterveningIdentical coalesces sufficiently short (<= windowSize) +// equal groups into adjacent unequal groups that currently result in a +// dual inserted/removed printout. This acts as a high-pass filter to smooth +// out high-frequency changes within the windowSize. +func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats { + groups, groupsOrig := groups[:0], groups + for i, ds := range groupsOrig { + if len(groups) >= 2 && ds.NumDiff() > 0 { + prev := &groups[len(groups)-2] // Unequal group + curr := &groups[len(groups)-1] // Equal group + next := &groupsOrig[i] // Unequal group + hadX, hadY := prev.NumRemoved > 0, prev.NumInserted > 0 + hasX, hasY := next.NumRemoved > 0, next.NumInserted > 0 + if ((hadX || hasX) && (hadY || hasY)) && curr.NumIdentical <= windowSize { + *prev = prev.Append(*curr).Append(*next) + groups = groups[:len(groups)-1] // Truncate off equal group + continue + } + } + groups = append(groups, ds) + } + return groups +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_text.go b/vendor/github.com/google/go-cmp/cmp/report_text.go new file mode 100644 index 00000000..8b12c05c --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_text.go @@ -0,0 +1,431 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import ( + "bytes" + "fmt" + "math/rand" + "strings" + "time" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/flags" +) + +var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 + +const maxColumnLength = 80 + +type indentMode int + +func (n indentMode) appendIndent(b []byte, d diffMode) []byte { + // The output of Diff is documented as being unstable to provide future + // flexibility in changing the output for more humanly readable reports. + // This logic intentionally introduces instability to the exact output + // so that users can detect accidental reliance on stability early on, + // rather than much later when an actual change to the format occurs. + if flags.Deterministic || randBool { + // Use regular spaces (U+0020). + switch d { + case diffUnknown, diffIdentical: + b = append(b, " "...) + case diffRemoved: + b = append(b, "- "...) + case diffInserted: + b = append(b, "+ "...) + } + } else { + // Use non-breaking spaces (U+00a0). + switch d { + case diffUnknown, diffIdentical: + b = append(b, "  "...) + case diffRemoved: + b = append(b, "- "...) + case diffInserted: + b = append(b, "+ "...) + } + } + return repeatCount(n).appendChar(b, '\t') +} + +type repeatCount int + +func (n repeatCount) appendChar(b []byte, c byte) []byte { + for ; n > 0; n-- { + b = append(b, c) + } + return b +} + +// textNode is a simplified tree-based representation of structured text. +// Possible node types are textWrap, textList, or textLine. +type textNode interface { + // Len reports the length in bytes of a single-line version of the tree. + // Nested textRecord.Diff and textRecord.Comment fields are ignored. + Len() int + // Equal reports whether the two trees are structurally identical. + // Nested textRecord.Diff and textRecord.Comment fields are compared. + Equal(textNode) bool + // String returns the string representation of the text tree. + // It is not guaranteed that len(x.String()) == x.Len(), + // nor that x.String() == y.String() implies that x.Equal(y). + String() string + + // formatCompactTo formats the contents of the tree as a single-line string + // to the provided buffer. Any nested textRecord.Diff and textRecord.Comment + // fields are ignored. + // + // However, not all nodes in the tree should be collapsed as a single-line. + // If a node can be collapsed as a single-line, it is replaced by a textLine + // node. Since the top-level node cannot replace itself, this also returns + // the current node itself. + // + // This does not mutate the receiver. + formatCompactTo([]byte, diffMode) ([]byte, textNode) + // formatExpandedTo formats the contents of the tree as a multi-line string + // to the provided buffer. In order for column alignment to operate well, + // formatCompactTo must be called before calling formatExpandedTo. + formatExpandedTo([]byte, diffMode, indentMode) []byte +} + +// textWrap is a wrapper that concatenates a prefix and/or a suffix +// to the underlying node. +type textWrap struct { + Prefix string // e.g., "bytes.Buffer{" + Value textNode // textWrap | textList | textLine + Suffix string // e.g., "}" + Metadata interface{} // arbitrary metadata; has no effect on formatting +} + +func (s *textWrap) Len() int { + return len(s.Prefix) + s.Value.Len() + len(s.Suffix) +} +func (s1 *textWrap) Equal(s2 textNode) bool { + if s2, ok := s2.(*textWrap); ok { + return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix + } + return false +} +func (s *textWrap) String() string { + var d diffMode + var n indentMode + _, s2 := s.formatCompactTo(nil, d) + b := n.appendIndent(nil, d) // Leading indent + b = s2.formatExpandedTo(b, d, n) // Main body + b = append(b, '\n') // Trailing newline + return string(b) +} +func (s *textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { + n0 := len(b) // Original buffer length + b = append(b, s.Prefix...) + b, s.Value = s.Value.formatCompactTo(b, d) + b = append(b, s.Suffix...) + if _, ok := s.Value.(textLine); ok { + return b, textLine(b[n0:]) + } + return b, s +} +func (s *textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { + b = append(b, s.Prefix...) + b = s.Value.formatExpandedTo(b, d, n) + b = append(b, s.Suffix...) + return b +} + +// textList is a comma-separated list of textWrap or textLine nodes. +// The list may be formatted as multi-lines or single-line at the discretion +// of the textList.formatCompactTo method. +type textList []textRecord +type textRecord struct { + Diff diffMode // e.g., 0 or '-' or '+' + Key string // e.g., "MyField" + Value textNode // textWrap | textLine + ElideComma bool // avoid trailing comma + Comment fmt.Stringer // e.g., "6 identical fields" +} + +// AppendEllipsis appends a new ellipsis node to the list if none already +// exists at the end. If cs is non-zero it coalesces the statistics with the +// previous diffStats. +func (s *textList) AppendEllipsis(ds diffStats) { + hasStats := !ds.IsZero() + if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) { + if hasStats { + *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds}) + } else { + *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true}) + } + return + } + if hasStats { + (*s)[len(*s)-1].Comment = (*s)[len(*s)-1].Comment.(diffStats).Append(ds) + } +} + +func (s textList) Len() (n int) { + for i, r := range s { + n += len(r.Key) + if r.Key != "" { + n += len(": ") + } + n += r.Value.Len() + if i < len(s)-1 { + n += len(", ") + } + } + return n +} + +func (s1 textList) Equal(s2 textNode) bool { + if s2, ok := s2.(textList); ok { + if len(s1) != len(s2) { + return false + } + for i := range s1 { + r1, r2 := s1[i], s2[i] + if !(r1.Diff == r2.Diff && r1.Key == r2.Key && r1.Value.Equal(r2.Value) && r1.Comment == r2.Comment) { + return false + } + } + return true + } + return false +} + +func (s textList) String() string { + return (&textWrap{Prefix: "{", Value: s, Suffix: "}"}).String() +} + +func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { + s = append(textList(nil), s...) // Avoid mutating original + + // Determine whether we can collapse this list as a single line. + n0 := len(b) // Original buffer length + var multiLine bool + for i, r := range s { + if r.Diff == diffInserted || r.Diff == diffRemoved { + multiLine = true + } + b = append(b, r.Key...) + if r.Key != "" { + b = append(b, ": "...) + } + b, s[i].Value = r.Value.formatCompactTo(b, d|r.Diff) + if _, ok := s[i].Value.(textLine); !ok { + multiLine = true + } + if r.Comment != nil { + multiLine = true + } + if i < len(s)-1 { + b = append(b, ", "...) + } + } + // Force multi-lined output when printing a removed/inserted node that + // is sufficiently long. + if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > maxColumnLength { + multiLine = true + } + if !multiLine { + return b, textLine(b[n0:]) + } + return b, s +} + +func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { + alignKeyLens := s.alignLens( + func(r textRecord) bool { + _, isLine := r.Value.(textLine) + return r.Key == "" || !isLine + }, + func(r textRecord) int { return utf8.RuneCountInString(r.Key) }, + ) + alignValueLens := s.alignLens( + func(r textRecord) bool { + _, isLine := r.Value.(textLine) + return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil + }, + func(r textRecord) int { return utf8.RuneCount(r.Value.(textLine)) }, + ) + + // Format lists of simple lists in a batched form. + // If the list is sequence of only textLine values, + // then batch multiple values on a single line. + var isSimple bool + for _, r := range s { + _, isLine := r.Value.(textLine) + isSimple = r.Diff == 0 && r.Key == "" && isLine && r.Comment == nil + if !isSimple { + break + } + } + if isSimple { + n++ + var batch []byte + emitBatch := func() { + if len(batch) > 0 { + b = n.appendIndent(append(b, '\n'), d) + b = append(b, bytes.TrimRight(batch, " ")...) + batch = batch[:0] + } + } + for _, r := range s { + line := r.Value.(textLine) + if len(batch)+len(line)+len(", ") > maxColumnLength { + emitBatch() + } + batch = append(batch, line...) + batch = append(batch, ", "...) + } + emitBatch() + n-- + return n.appendIndent(append(b, '\n'), d) + } + + // Format the list as a multi-lined output. + n++ + for i, r := range s { + b = n.appendIndent(append(b, '\n'), d|r.Diff) + if r.Key != "" { + b = append(b, r.Key+": "...) + } + b = alignKeyLens[i].appendChar(b, ' ') + + b = r.Value.formatExpandedTo(b, d|r.Diff, n) + if !r.ElideComma { + b = append(b, ',') + } + b = alignValueLens[i].appendChar(b, ' ') + + if r.Comment != nil { + b = append(b, " // "+r.Comment.String()...) + } + } + n-- + + return n.appendIndent(append(b, '\n'), d) +} + +func (s textList) alignLens( + skipFunc func(textRecord) bool, + lenFunc func(textRecord) int, +) []repeatCount { + var startIdx, endIdx, maxLen int + lens := make([]repeatCount, len(s)) + for i, r := range s { + if skipFunc(r) { + for j := startIdx; j < endIdx && j < len(s); j++ { + lens[j] = repeatCount(maxLen - lenFunc(s[j])) + } + startIdx, endIdx, maxLen = i+1, i+1, 0 + } else { + if maxLen < lenFunc(r) { + maxLen = lenFunc(r) + } + endIdx = i + 1 + } + } + for j := startIdx; j < endIdx && j < len(s); j++ { + lens[j] = repeatCount(maxLen - lenFunc(s[j])) + } + return lens +} + +// textLine is a single-line segment of text and is always a leaf node +// in the textNode tree. +type textLine []byte + +var ( + textNil = textLine("nil") + textEllipsis = textLine("...") +) + +func (s textLine) Len() int { + return len(s) +} +func (s1 textLine) Equal(s2 textNode) bool { + if s2, ok := s2.(textLine); ok { + return bytes.Equal([]byte(s1), []byte(s2)) + } + return false +} +func (s textLine) String() string { + return string(s) +} +func (s textLine) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { + return append(b, s...), s +} +func (s textLine) formatExpandedTo(b []byte, _ diffMode, _ indentMode) []byte { + return append(b, s...) +} + +type diffStats struct { + Name string + NumIgnored int + NumIdentical int + NumRemoved int + NumInserted int + NumModified int +} + +func (s diffStats) IsZero() bool { + s.Name = "" + return s == diffStats{} +} + +func (s diffStats) NumDiff() int { + return s.NumRemoved + s.NumInserted + s.NumModified +} + +func (s diffStats) Append(ds diffStats) diffStats { + assert(s.Name == ds.Name) + s.NumIgnored += ds.NumIgnored + s.NumIdentical += ds.NumIdentical + s.NumRemoved += ds.NumRemoved + s.NumInserted += ds.NumInserted + s.NumModified += ds.NumModified + return s +} + +// String prints a humanly-readable summary of coalesced records. +// +// Example: +// diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields" +func (s diffStats) String() string { + var ss []string + var sum int + labels := [...]string{"ignored", "identical", "removed", "inserted", "modified"} + counts := [...]int{s.NumIgnored, s.NumIdentical, s.NumRemoved, s.NumInserted, s.NumModified} + for i, n := range counts { + if n > 0 { + ss = append(ss, fmt.Sprintf("%d %v", n, labels[i])) + } + sum += n + } + + // Pluralize the name (adjusting for some obscure English grammar rules). + name := s.Name + if sum > 1 { + name += "s" + if strings.HasSuffix(name, "ys") { + name = name[:len(name)-2] + "ies" // e.g., "entrys" => "entries" + } + } + + // Format the list according to English grammar (with Oxford comma). + switch n := len(ss); n { + case 0: + return "" + case 1, 2: + return strings.Join(ss, " and ") + " " + name + default: + return strings.Join(ss[:n-1], ", ") + ", and " + ss[n-1] + " " + name + } +} + +type commentString string + +func (s commentString) String() string { return string(s) } diff --git a/vendor/github.com/google/go-cmp/cmp/report_value.go b/vendor/github.com/google/go-cmp/cmp/report_value.go new file mode 100644 index 00000000..83031a7f --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_value.go @@ -0,0 +1,121 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmp + +import "reflect" + +// valueNode represents a single node within a report, which is a +// structured representation of the value tree, containing information +// regarding which nodes are equal or not. +type valueNode struct { + parent *valueNode + + Type reflect.Type + ValueX reflect.Value + ValueY reflect.Value + + // NumSame is the number of leaf nodes that are equal. + // All descendants are equal only if NumDiff is 0. + NumSame int + // NumDiff is the number of leaf nodes that are not equal. + NumDiff int + // NumIgnored is the number of leaf nodes that are ignored. + NumIgnored int + // NumCompared is the number of leaf nodes that were compared + // using an Equal method or Comparer function. + NumCompared int + // NumTransformed is the number of non-leaf nodes that were transformed. + NumTransformed int + // NumChildren is the number of transitive descendants of this node. + // This counts from zero; thus, leaf nodes have no descendants. + NumChildren int + // MaxDepth is the maximum depth of the tree. This counts from zero; + // thus, leaf nodes have a depth of zero. + MaxDepth int + + // Records is a list of struct fields, slice elements, or map entries. + Records []reportRecord // If populated, implies Value is not populated + + // Value is the result of a transformation, pointer indirect, of + // type assertion. + Value *valueNode // If populated, implies Records is not populated + + // TransformerName is the name of the transformer. + TransformerName string // If non-empty, implies Value is populated +} +type reportRecord struct { + Key reflect.Value // Invalid for slice element + Value *valueNode +} + +func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) { + vx, vy := ps.Values() + child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy} + switch s := ps.(type) { + case StructField: + assert(parent.Value == nil) + parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child}) + case SliceIndex: + assert(parent.Value == nil) + parent.Records = append(parent.Records, reportRecord{Value: child}) + case MapIndex: + assert(parent.Value == nil) + parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child}) + case Indirect: + assert(parent.Value == nil && parent.Records == nil) + parent.Value = child + case TypeAssertion: + assert(parent.Value == nil && parent.Records == nil) + parent.Value = child + case Transform: + assert(parent.Value == nil && parent.Records == nil) + parent.Value = child + parent.TransformerName = s.Name() + parent.NumTransformed++ + default: + assert(parent == nil) // Must be the root step + } + return child +} + +func (r *valueNode) Report(rs Result) { + assert(r.MaxDepth == 0) // May only be called on leaf nodes + + if rs.ByIgnore() { + r.NumIgnored++ + } else { + if rs.Equal() { + r.NumSame++ + } else { + r.NumDiff++ + } + } + assert(r.NumSame+r.NumDiff+r.NumIgnored == 1) + + if rs.ByMethod() { + r.NumCompared++ + } + if rs.ByFunc() { + r.NumCompared++ + } + assert(r.NumCompared <= 1) +} + +func (child *valueNode) PopStep() (parent *valueNode) { + if child.parent == nil { + return nil + } + parent = child.parent + parent.NumSame += child.NumSame + parent.NumDiff += child.NumDiff + parent.NumIgnored += child.NumIgnored + parent.NumCompared += child.NumCompared + parent.NumTransformed += child.NumTransformed + parent.NumChildren += child.NumChildren + 1 + if parent.MaxDepth < child.MaxDepth+1 { + parent.MaxDepth = child.MaxDepth + 1 + } + return parent +} diff --git a/vendor/github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.pb.go b/vendor/github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.pb.go new file mode 100644 index 00000000..9ba7f6a4 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.pb.go @@ -0,0 +1,1077 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto + +package v1alpha1 + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// 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 + +type AuthenticationType int32 + +const ( + // No authentication is used + AuthenticationType_NONE AuthenticationType = 0 + // One way CHAP authentication. The target authenticates the initiator. + AuthenticationType_ONE_WAY_CHAP AuthenticationType = 1 + // Mutual CHAP authentication. The target and initiator authenticate each + // other. + AuthenticationType_MUTUAL_CHAP AuthenticationType = 2 +) + +var AuthenticationType_name = map[int32]string{ + 0: "NONE", + 1: "ONE_WAY_CHAP", + 2: "MUTUAL_CHAP", +} + +var AuthenticationType_value = map[string]int32{ + "NONE": 0, + "ONE_WAY_CHAP": 1, + "MUTUAL_CHAP": 2, +} + +func (x AuthenticationType) String() string { + return proto.EnumName(AuthenticationType_name, int32(x)) +} + +func (AuthenticationType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{0} +} + +// TargetPortal is an address and port pair for a specific iSCSI storage +// target. +type TargetPortal struct { + // iSCSI Target (server) address + TargetAddress string `protobuf:"bytes,1,opt,name=target_address,json=targetAddress,proto3" json:"target_address,omitempty"` + // iSCSI Target port (default iSCSI port is 3260) + TargetPort uint32 `protobuf:"varint,2,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TargetPortal) Reset() { *m = TargetPortal{} } +func (m *TargetPortal) String() string { return proto.CompactTextString(m) } +func (*TargetPortal) ProtoMessage() {} +func (*TargetPortal) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{0} +} + +func (m *TargetPortal) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TargetPortal.Unmarshal(m, b) +} +func (m *TargetPortal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TargetPortal.Marshal(b, m, deterministic) +} +func (m *TargetPortal) XXX_Merge(src proto.Message) { + xxx_messageInfo_TargetPortal.Merge(m, src) +} +func (m *TargetPortal) XXX_Size() int { + return xxx_messageInfo_TargetPortal.Size(m) +} +func (m *TargetPortal) XXX_DiscardUnknown() { + xxx_messageInfo_TargetPortal.DiscardUnknown(m) +} + +var xxx_messageInfo_TargetPortal proto.InternalMessageInfo + +func (m *TargetPortal) GetTargetAddress() string { + if m != nil { + return m.TargetAddress + } + return "" +} + +func (m *TargetPortal) GetTargetPort() uint32 { + if m != nil { + return m.TargetPort + } + return 0 +} + +type AddTargetPortalRequest struct { + // iSCSI Target Portal to register in the initiator + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddTargetPortalRequest) Reset() { *m = AddTargetPortalRequest{} } +func (m *AddTargetPortalRequest) String() string { return proto.CompactTextString(m) } +func (*AddTargetPortalRequest) ProtoMessage() {} +func (*AddTargetPortalRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{1} +} + +func (m *AddTargetPortalRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddTargetPortalRequest.Unmarshal(m, b) +} +func (m *AddTargetPortalRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddTargetPortalRequest.Marshal(b, m, deterministic) +} +func (m *AddTargetPortalRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddTargetPortalRequest.Merge(m, src) +} +func (m *AddTargetPortalRequest) XXX_Size() int { + return xxx_messageInfo_AddTargetPortalRequest.Size(m) +} +func (m *AddTargetPortalRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AddTargetPortalRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AddTargetPortalRequest proto.InternalMessageInfo + +func (m *AddTargetPortalRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +type AddTargetPortalResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddTargetPortalResponse) Reset() { *m = AddTargetPortalResponse{} } +func (m *AddTargetPortalResponse) String() string { return proto.CompactTextString(m) } +func (*AddTargetPortalResponse) ProtoMessage() {} +func (*AddTargetPortalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{2} +} + +func (m *AddTargetPortalResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddTargetPortalResponse.Unmarshal(m, b) +} +func (m *AddTargetPortalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddTargetPortalResponse.Marshal(b, m, deterministic) +} +func (m *AddTargetPortalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddTargetPortalResponse.Merge(m, src) +} +func (m *AddTargetPortalResponse) XXX_Size() int { + return xxx_messageInfo_AddTargetPortalResponse.Size(m) +} +func (m *AddTargetPortalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AddTargetPortalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AddTargetPortalResponse proto.InternalMessageInfo + +type DiscoverTargetPortalRequest struct { + // iSCSI Target Portal on which to initiate discovery + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DiscoverTargetPortalRequest) Reset() { *m = DiscoverTargetPortalRequest{} } +func (m *DiscoverTargetPortalRequest) String() string { return proto.CompactTextString(m) } +func (*DiscoverTargetPortalRequest) ProtoMessage() {} +func (*DiscoverTargetPortalRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{3} +} + +func (m *DiscoverTargetPortalRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DiscoverTargetPortalRequest.Unmarshal(m, b) +} +func (m *DiscoverTargetPortalRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DiscoverTargetPortalRequest.Marshal(b, m, deterministic) +} +func (m *DiscoverTargetPortalRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DiscoverTargetPortalRequest.Merge(m, src) +} +func (m *DiscoverTargetPortalRequest) XXX_Size() int { + return xxx_messageInfo_DiscoverTargetPortalRequest.Size(m) +} +func (m *DiscoverTargetPortalRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DiscoverTargetPortalRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DiscoverTargetPortalRequest proto.InternalMessageInfo + +func (m *DiscoverTargetPortalRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +type DiscoverTargetPortalResponse struct { + // List of discovered IQN addresses + // follows IQN format: iqn.yyyy-mm.naming-authority:unique-name + Iqns []string `protobuf:"bytes,1,rep,name=iqns,proto3" json:"iqns,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DiscoverTargetPortalResponse) Reset() { *m = DiscoverTargetPortalResponse{} } +func (m *DiscoverTargetPortalResponse) String() string { return proto.CompactTextString(m) } +func (*DiscoverTargetPortalResponse) ProtoMessage() {} +func (*DiscoverTargetPortalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{4} +} + +func (m *DiscoverTargetPortalResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DiscoverTargetPortalResponse.Unmarshal(m, b) +} +func (m *DiscoverTargetPortalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DiscoverTargetPortalResponse.Marshal(b, m, deterministic) +} +func (m *DiscoverTargetPortalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DiscoverTargetPortalResponse.Merge(m, src) +} +func (m *DiscoverTargetPortalResponse) XXX_Size() int { + return xxx_messageInfo_DiscoverTargetPortalResponse.Size(m) +} +func (m *DiscoverTargetPortalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DiscoverTargetPortalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DiscoverTargetPortalResponse proto.InternalMessageInfo + +func (m *DiscoverTargetPortalResponse) GetIqns() []string { + if m != nil { + return m.Iqns + } + return nil +} + +type RemoveTargetPortalRequest struct { + // iSCSI Target Portal + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveTargetPortalRequest) Reset() { *m = RemoveTargetPortalRequest{} } +func (m *RemoveTargetPortalRequest) String() string { return proto.CompactTextString(m) } +func (*RemoveTargetPortalRequest) ProtoMessage() {} +func (*RemoveTargetPortalRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{5} +} + +func (m *RemoveTargetPortalRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveTargetPortalRequest.Unmarshal(m, b) +} +func (m *RemoveTargetPortalRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveTargetPortalRequest.Marshal(b, m, deterministic) +} +func (m *RemoveTargetPortalRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveTargetPortalRequest.Merge(m, src) +} +func (m *RemoveTargetPortalRequest) XXX_Size() int { + return xxx_messageInfo_RemoveTargetPortalRequest.Size(m) +} +func (m *RemoveTargetPortalRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveTargetPortalRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveTargetPortalRequest proto.InternalMessageInfo + +func (m *RemoveTargetPortalRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +type RemoveTargetPortalResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveTargetPortalResponse) Reset() { *m = RemoveTargetPortalResponse{} } +func (m *RemoveTargetPortalResponse) String() string { return proto.CompactTextString(m) } +func (*RemoveTargetPortalResponse) ProtoMessage() {} +func (*RemoveTargetPortalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{6} +} + +func (m *RemoveTargetPortalResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveTargetPortalResponse.Unmarshal(m, b) +} +func (m *RemoveTargetPortalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveTargetPortalResponse.Marshal(b, m, deterministic) +} +func (m *RemoveTargetPortalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveTargetPortalResponse.Merge(m, src) +} +func (m *RemoveTargetPortalResponse) XXX_Size() int { + return xxx_messageInfo_RemoveTargetPortalResponse.Size(m) +} +func (m *RemoveTargetPortalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveTargetPortalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveTargetPortalResponse proto.InternalMessageInfo + +type ListTargetPortalsRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTargetPortalsRequest) Reset() { *m = ListTargetPortalsRequest{} } +func (m *ListTargetPortalsRequest) String() string { return proto.CompactTextString(m) } +func (*ListTargetPortalsRequest) ProtoMessage() {} +func (*ListTargetPortalsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{7} +} + +func (m *ListTargetPortalsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListTargetPortalsRequest.Unmarshal(m, b) +} +func (m *ListTargetPortalsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListTargetPortalsRequest.Marshal(b, m, deterministic) +} +func (m *ListTargetPortalsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTargetPortalsRequest.Merge(m, src) +} +func (m *ListTargetPortalsRequest) XXX_Size() int { + return xxx_messageInfo_ListTargetPortalsRequest.Size(m) +} +func (m *ListTargetPortalsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListTargetPortalsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListTargetPortalsRequest proto.InternalMessageInfo + +type ListTargetPortalsResponse struct { + // A list of Target Portals currently registered in the initiator + TargetPortals []*TargetPortal `protobuf:"bytes,1,rep,name=target_portals,json=targetPortals,proto3" json:"target_portals,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTargetPortalsResponse) Reset() { *m = ListTargetPortalsResponse{} } +func (m *ListTargetPortalsResponse) String() string { return proto.CompactTextString(m) } +func (*ListTargetPortalsResponse) ProtoMessage() {} +func (*ListTargetPortalsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{8} +} + +func (m *ListTargetPortalsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListTargetPortalsResponse.Unmarshal(m, b) +} +func (m *ListTargetPortalsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListTargetPortalsResponse.Marshal(b, m, deterministic) +} +func (m *ListTargetPortalsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTargetPortalsResponse.Merge(m, src) +} +func (m *ListTargetPortalsResponse) XXX_Size() int { + return xxx_messageInfo_ListTargetPortalsResponse.Size(m) +} +func (m *ListTargetPortalsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListTargetPortalsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListTargetPortalsResponse proto.InternalMessageInfo + +func (m *ListTargetPortalsResponse) GetTargetPortals() []*TargetPortal { + if m != nil { + return m.TargetPortals + } + return nil +} + +type ConnectTargetRequest struct { + // Target portal to which the initiator will connect + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + // IQN of the iSCSI Target + Iqn string `protobuf:"bytes,2,opt,name=iqn,proto3" json:"iqn,omitempty"` + // Connection authentication type, None by default + // + // One Way Chap uses the chap_username and chap_secret + // fields mentioned below to authenticate the initiator. + // + // Mutual Chap uses both the user/secret mentioned below + // and the Initiator Chap Secret to authenticate the target and initiator. + AuthType AuthenticationType `protobuf:"varint,3,opt,name=auth_type,json=authType,proto3,enum=v1alpha1.AuthenticationType" json:"auth_type,omitempty"` + // CHAP Username used to authenticate the initiator + ChapUsername string `protobuf:"bytes,4,opt,name=chap_username,json=chapUsername,proto3" json:"chap_username,omitempty"` + // CHAP password used to authenticate the initiator + ChapSecret string `protobuf:"bytes,5,opt,name=chap_secret,json=chapSecret,proto3" json:"chap_secret,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConnectTargetRequest) Reset() { *m = ConnectTargetRequest{} } +func (m *ConnectTargetRequest) String() string { return proto.CompactTextString(m) } +func (*ConnectTargetRequest) ProtoMessage() {} +func (*ConnectTargetRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{9} +} + +func (m *ConnectTargetRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConnectTargetRequest.Unmarshal(m, b) +} +func (m *ConnectTargetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConnectTargetRequest.Marshal(b, m, deterministic) +} +func (m *ConnectTargetRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConnectTargetRequest.Merge(m, src) +} +func (m *ConnectTargetRequest) XXX_Size() int { + return xxx_messageInfo_ConnectTargetRequest.Size(m) +} +func (m *ConnectTargetRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ConnectTargetRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ConnectTargetRequest proto.InternalMessageInfo + +func (m *ConnectTargetRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +func (m *ConnectTargetRequest) GetIqn() string { + if m != nil { + return m.Iqn + } + return "" +} + +func (m *ConnectTargetRequest) GetAuthType() AuthenticationType { + if m != nil { + return m.AuthType + } + return AuthenticationType_NONE +} + +func (m *ConnectTargetRequest) GetChapUsername() string { + if m != nil { + return m.ChapUsername + } + return "" +} + +func (m *ConnectTargetRequest) GetChapSecret() string { + if m != nil { + return m.ChapSecret + } + return "" +} + +type ConnectTargetResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConnectTargetResponse) Reset() { *m = ConnectTargetResponse{} } +func (m *ConnectTargetResponse) String() string { return proto.CompactTextString(m) } +func (*ConnectTargetResponse) ProtoMessage() {} +func (*ConnectTargetResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{10} +} + +func (m *ConnectTargetResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConnectTargetResponse.Unmarshal(m, b) +} +func (m *ConnectTargetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConnectTargetResponse.Marshal(b, m, deterministic) +} +func (m *ConnectTargetResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConnectTargetResponse.Merge(m, src) +} +func (m *ConnectTargetResponse) XXX_Size() int { + return xxx_messageInfo_ConnectTargetResponse.Size(m) +} +func (m *ConnectTargetResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ConnectTargetResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ConnectTargetResponse proto.InternalMessageInfo + +type GetTargetDisksRequest struct { + // Target portal whose disks will be queried + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + // IQN of the iSCSI Target + Iqn string `protobuf:"bytes,2,opt,name=iqn,proto3" json:"iqn,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTargetDisksRequest) Reset() { *m = GetTargetDisksRequest{} } +func (m *GetTargetDisksRequest) String() string { return proto.CompactTextString(m) } +func (*GetTargetDisksRequest) ProtoMessage() {} +func (*GetTargetDisksRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{11} +} + +func (m *GetTargetDisksRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTargetDisksRequest.Unmarshal(m, b) +} +func (m *GetTargetDisksRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTargetDisksRequest.Marshal(b, m, deterministic) +} +func (m *GetTargetDisksRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTargetDisksRequest.Merge(m, src) +} +func (m *GetTargetDisksRequest) XXX_Size() int { + return xxx_messageInfo_GetTargetDisksRequest.Size(m) +} +func (m *GetTargetDisksRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetTargetDisksRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTargetDisksRequest proto.InternalMessageInfo + +func (m *GetTargetDisksRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +func (m *GetTargetDisksRequest) GetIqn() string { + if m != nil { + return m.Iqn + } + return "" +} + +type GetTargetDisksResponse struct { + // List composed of disk ids (numbers) that are associated with the + // iSCSI target + DiskIDs []string `protobuf:"bytes,1,rep,name=diskIDs,proto3" json:"diskIDs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTargetDisksResponse) Reset() { *m = GetTargetDisksResponse{} } +func (m *GetTargetDisksResponse) String() string { return proto.CompactTextString(m) } +func (*GetTargetDisksResponse) ProtoMessage() {} +func (*GetTargetDisksResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{12} +} + +func (m *GetTargetDisksResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTargetDisksResponse.Unmarshal(m, b) +} +func (m *GetTargetDisksResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTargetDisksResponse.Marshal(b, m, deterministic) +} +func (m *GetTargetDisksResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTargetDisksResponse.Merge(m, src) +} +func (m *GetTargetDisksResponse) XXX_Size() int { + return xxx_messageInfo_GetTargetDisksResponse.Size(m) +} +func (m *GetTargetDisksResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetTargetDisksResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTargetDisksResponse proto.InternalMessageInfo + +func (m *GetTargetDisksResponse) GetDiskIDs() []string { + if m != nil { + return m.DiskIDs + } + return nil +} + +type DisconnectTargetRequest struct { + // Target portal from which initiator will disconnect + TargetPortal *TargetPortal `protobuf:"bytes,1,opt,name=target_portal,json=targetPortal,proto3" json:"target_portal,omitempty"` + // IQN of the iSCSI Target + Iqn string `protobuf:"bytes,2,opt,name=iqn,proto3" json:"iqn,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DisconnectTargetRequest) Reset() { *m = DisconnectTargetRequest{} } +func (m *DisconnectTargetRequest) String() string { return proto.CompactTextString(m) } +func (*DisconnectTargetRequest) ProtoMessage() {} +func (*DisconnectTargetRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{13} +} + +func (m *DisconnectTargetRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DisconnectTargetRequest.Unmarshal(m, b) +} +func (m *DisconnectTargetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DisconnectTargetRequest.Marshal(b, m, deterministic) +} +func (m *DisconnectTargetRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DisconnectTargetRequest.Merge(m, src) +} +func (m *DisconnectTargetRequest) XXX_Size() int { + return xxx_messageInfo_DisconnectTargetRequest.Size(m) +} +func (m *DisconnectTargetRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DisconnectTargetRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DisconnectTargetRequest proto.InternalMessageInfo + +func (m *DisconnectTargetRequest) GetTargetPortal() *TargetPortal { + if m != nil { + return m.TargetPortal + } + return nil +} + +func (m *DisconnectTargetRequest) GetIqn() string { + if m != nil { + return m.Iqn + } + return "" +} + +type DisconnectTargetResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DisconnectTargetResponse) Reset() { *m = DisconnectTargetResponse{} } +func (m *DisconnectTargetResponse) String() string { return proto.CompactTextString(m) } +func (*DisconnectTargetResponse) ProtoMessage() {} +func (*DisconnectTargetResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0438d9bfe30f1df4, []int{14} +} + +func (m *DisconnectTargetResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DisconnectTargetResponse.Unmarshal(m, b) +} +func (m *DisconnectTargetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DisconnectTargetResponse.Marshal(b, m, deterministic) +} +func (m *DisconnectTargetResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DisconnectTargetResponse.Merge(m, src) +} +func (m *DisconnectTargetResponse) XXX_Size() int { + return xxx_messageInfo_DisconnectTargetResponse.Size(m) +} +func (m *DisconnectTargetResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DisconnectTargetResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DisconnectTargetResponse proto.InternalMessageInfo + +func init() { + proto.RegisterEnum("v1alpha1.AuthenticationType", AuthenticationType_name, AuthenticationType_value) + proto.RegisterType((*TargetPortal)(nil), "v1alpha1.TargetPortal") + proto.RegisterType((*AddTargetPortalRequest)(nil), "v1alpha1.AddTargetPortalRequest") + proto.RegisterType((*AddTargetPortalResponse)(nil), "v1alpha1.AddTargetPortalResponse") + proto.RegisterType((*DiscoverTargetPortalRequest)(nil), "v1alpha1.DiscoverTargetPortalRequest") + proto.RegisterType((*DiscoverTargetPortalResponse)(nil), "v1alpha1.DiscoverTargetPortalResponse") + proto.RegisterType((*RemoveTargetPortalRequest)(nil), "v1alpha1.RemoveTargetPortalRequest") + proto.RegisterType((*RemoveTargetPortalResponse)(nil), "v1alpha1.RemoveTargetPortalResponse") + proto.RegisterType((*ListTargetPortalsRequest)(nil), "v1alpha1.ListTargetPortalsRequest") + proto.RegisterType((*ListTargetPortalsResponse)(nil), "v1alpha1.ListTargetPortalsResponse") + proto.RegisterType((*ConnectTargetRequest)(nil), "v1alpha1.ConnectTargetRequest") + proto.RegisterType((*ConnectTargetResponse)(nil), "v1alpha1.ConnectTargetResponse") + proto.RegisterType((*GetTargetDisksRequest)(nil), "v1alpha1.GetTargetDisksRequest") + proto.RegisterType((*GetTargetDisksResponse)(nil), "v1alpha1.GetTargetDisksResponse") + proto.RegisterType((*DisconnectTargetRequest)(nil), "v1alpha1.DisconnectTargetRequest") + proto.RegisterType((*DisconnectTargetResponse)(nil), "v1alpha1.DisconnectTargetResponse") +} + +func init() { + proto.RegisterFile("github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto", fileDescriptor_0438d9bfe30f1df4) +} + +var fileDescriptor_0438d9bfe30f1df4 = []byte{ + // 649 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x6d, 0x4f, 0xd3, 0x50, + 0x14, 0xa6, 0xbc, 0x28, 0x3b, 0xac, 0x30, 0x6f, 0x78, 0x29, 0x95, 0xc8, 0xb8, 0x88, 0x59, 0x4c, + 0xd8, 0xc2, 0xfc, 0x64, 0x0c, 0x31, 0x15, 0x08, 0x92, 0x20, 0x90, 0xca, 0x14, 0x67, 0xe2, 0x72, + 0xd7, 0x5d, 0xd7, 0x9b, 0x6d, 0x6d, 0xd7, 0x7b, 0xbb, 0xb8, 0x1f, 0xe2, 0x5f, 0xf4, 0x77, 0x98, + 0xbe, 0xac, 0xeb, 0xb6, 0x6e, 0x7e, 0x70, 0x7c, 0xeb, 0x7d, 0xee, 0x73, 0x9e, 0x73, 0xee, 0x79, + 0x2b, 0x5c, 0x36, 0x99, 0x30, 0xbd, 0x7a, 0xd1, 0xb0, 0x3b, 0xa5, 0x96, 0x57, 0xa7, 0xae, 0x45, + 0x05, 0xe5, 0xc7, 0x06, 0x67, 0x25, 0x83, 0xb3, 0x63, 0xc7, 0xb5, 0x7f, 0xf5, 0x4b, 0x46, 0x9b, + 0x51, 0x4b, 0x94, 0x88, 0xc3, 0x4a, 0x8c, 0xfb, 0x57, 0xbd, 0x13, 0xd2, 0x76, 0x4c, 0x72, 0xe2, + 0x43, 0x45, 0xc7, 0xb5, 0x85, 0x8d, 0x56, 0x07, 0x18, 0xfe, 0x02, 0xd9, 0x7b, 0xe2, 0x36, 0xa9, + 0xb8, 0xb3, 0x5d, 0x41, 0xda, 0xe8, 0x08, 0xd6, 0x45, 0x70, 0xae, 0x91, 0x46, 0xc3, 0xa5, 0x9c, + 0x2b, 0x52, 0x5e, 0x2a, 0x64, 0x74, 0x39, 0x44, 0xb5, 0x10, 0x44, 0xfb, 0xb0, 0x16, 0xd1, 0x1c, + 0xdb, 0x15, 0xca, 0x62, 0x5e, 0x2a, 0xc8, 0x3a, 0x88, 0x58, 0x09, 0x57, 0x60, 0x5b, 0x6b, 0x34, + 0x92, 0xd2, 0x3a, 0xed, 0x7a, 0x94, 0x0b, 0xf4, 0x0e, 0xe4, 0x84, 0x29, 0x69, 0x07, 0x0e, 0xd6, + 0xca, 0xdb, 0xc5, 0x41, 0x4c, 0xc5, 0x11, 0xab, 0xac, 0x48, 0x9c, 0xf0, 0x2e, 0xec, 0x4c, 0xc8, + 0x72, 0xc7, 0xb6, 0x38, 0xc5, 0x55, 0x78, 0x7e, 0xce, 0xb8, 0x61, 0xf7, 0xa8, 0x3b, 0x77, 0xb7, + 0x65, 0xd8, 0x4b, 0xd7, 0x0e, 0x7d, 0x23, 0x04, 0xcb, 0xac, 0x6b, 0xf9, 0xb9, 0x5a, 0x2a, 0x64, + 0xf4, 0xe0, 0x1b, 0x3f, 0xc0, 0xae, 0x4e, 0x3b, 0x76, 0x8f, 0xce, 0x3d, 0x9a, 0x3d, 0x50, 0xd3, + 0x94, 0xa3, 0x3c, 0xa8, 0xa0, 0x5c, 0x33, 0x2e, 0x92, 0x77, 0x3c, 0x72, 0x8b, 0xab, 0xb0, 0x9b, + 0x72, 0x17, 0x3d, 0xe2, 0x34, 0x2e, 0x7d, 0x18, 0x53, 0xf8, 0x9c, 0xe9, 0x41, 0xc9, 0xc9, 0xa0, + 0x38, 0xfe, 0x23, 0xc1, 0xe6, 0x99, 0x6d, 0x59, 0xd4, 0x88, 0xf4, 0xe7, 0xf1, 0x56, 0x94, 0x83, + 0x25, 0xd6, 0xb5, 0x82, 0x06, 0xcb, 0xe8, 0xfe, 0x27, 0x7a, 0x0b, 0x19, 0xe2, 0x09, 0xb3, 0x26, + 0xfa, 0x0e, 0x55, 0x96, 0xf2, 0x52, 0x61, 0xbd, 0xbc, 0x37, 0x94, 0xd2, 0x3c, 0x61, 0x52, 0x4b, + 0x30, 0x83, 0x08, 0x66, 0x5b, 0xf7, 0x7d, 0x87, 0xea, 0xab, 0x3e, 0xdd, 0xff, 0x42, 0x87, 0x20, + 0x1b, 0x26, 0x71, 0x6a, 0x1e, 0xa7, 0xae, 0x45, 0x3a, 0x54, 0x59, 0x0e, 0x64, 0xb3, 0x3e, 0x58, + 0x89, 0x30, 0xbf, 0xb5, 0x03, 0x12, 0xa7, 0x86, 0x4b, 0x85, 0xb2, 0x12, 0x50, 0xc0, 0x87, 0x3e, + 0x07, 0x08, 0xde, 0x81, 0xad, 0xb1, 0x77, 0x46, 0x99, 0xff, 0x09, 0x5b, 0x97, 0x34, 0x02, 0xcf, + 0x19, 0x6f, 0xf1, 0xc7, 0xc9, 0x00, 0x2e, 0xc3, 0xf6, 0xb8, 0x9f, 0xa8, 0x84, 0x0a, 0x3c, 0x6d, + 0x30, 0xde, 0xba, 0x3a, 0x1f, 0xb4, 0xe2, 0xe0, 0x88, 0x4d, 0xd8, 0x09, 0x3a, 0xf8, 0xd1, 0xeb, + 0xe3, 0xf7, 0xdf, 0xa4, 0xa7, 0x30, 0xbe, 0xd7, 0x1a, 0xa0, 0xc9, 0x02, 0xa1, 0x55, 0x58, 0xbe, + 0xb9, 0xbd, 0xb9, 0xc8, 0x2d, 0xa0, 0x1c, 0x64, 0x6f, 0x6f, 0x2e, 0x6a, 0x5f, 0xb5, 0x6f, 0xb5, + 0xb3, 0x8f, 0xda, 0x5d, 0x4e, 0x42, 0x1b, 0xb0, 0xf6, 0xa9, 0x72, 0x5f, 0xd1, 0xae, 0x43, 0x60, + 0xb1, 0xfc, 0x7b, 0x05, 0x56, 0xae, 0xfc, 0xbd, 0x86, 0x1e, 0x60, 0x63, 0x6c, 0x17, 0xa0, 0x7c, + 0xa2, 0x11, 0x52, 0xb7, 0x8f, 0x7a, 0x30, 0x83, 0x11, 0x95, 0x71, 0x01, 0x35, 0x61, 0x33, 0x6d, + 0xdc, 0xd1, 0xd1, 0xd0, 0x78, 0xc6, 0xaa, 0x51, 0x5f, 0xfd, 0x8b, 0x16, 0x3b, 0x22, 0x80, 0x26, + 0x27, 0x19, 0x1d, 0x0e, 0xed, 0xa7, 0x6e, 0x10, 0xf5, 0xe5, 0x6c, 0x52, 0xec, 0xe2, 0x07, 0x3c, + 0x9b, 0x18, 0x79, 0x84, 0x87, 0xc6, 0xd3, 0x76, 0x85, 0x7a, 0x38, 0x93, 0x13, 0xeb, 0xeb, 0x20, + 0x8f, 0x4c, 0x03, 0x7a, 0x31, 0xb4, 0x4b, 0x5b, 0x07, 0xea, 0xfe, 0xd4, 0xfb, 0x58, 0xf3, 0x3b, + 0xe4, 0xc6, 0x5b, 0x08, 0x1d, 0x8c, 0x25, 0x35, 0x45, 0x19, 0xcf, 0xa2, 0xc4, 0xe2, 0x15, 0x58, + 0x1f, 0x9d, 0x1e, 0x94, 0x88, 0x28, 0x75, 0x7e, 0xd5, 0xfc, 0x74, 0xc2, 0x40, 0xf6, 0xc3, 0xfb, + 0xea, 0xe9, 0x7f, 0xfd, 0x9d, 0xeb, 0x4f, 0x82, 0x5f, 0xf3, 0x9b, 0xbf, 0x01, 0x00, 0x00, 0xff, + 0xff, 0xbb, 0x3d, 0x8f, 0x5c, 0xe5, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// IscsiClient is the client API for Iscsi service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type IscsiClient interface { + // AddTargetPortal registers an iSCSI target network address for later + // discovery. + // AddTargetPortal currently does not support selecting different NICs or + // a different iSCSI initiator (e.g a hardware initiator). This means that + // Windows will select the initiator NIC and instance on its own. + AddTargetPortal(ctx context.Context, in *AddTargetPortalRequest, opts ...grpc.CallOption) (*AddTargetPortalResponse, error) + // DiscoverTargetPortal initiates discovery on an iSCSI target network address + // and returns discovered IQNs. + DiscoverTargetPortal(ctx context.Context, in *DiscoverTargetPortalRequest, opts ...grpc.CallOption) (*DiscoverTargetPortalResponse, error) + // RemoveTargetPortal removes an iSCSI target network address registration. + RemoveTargetPortal(ctx context.Context, in *RemoveTargetPortalRequest, opts ...grpc.CallOption) (*RemoveTargetPortalResponse, error) + // ListTargetPortal lists all currently registered iSCSI target network + // addresses. + ListTargetPortals(ctx context.Context, in *ListTargetPortalsRequest, opts ...grpc.CallOption) (*ListTargetPortalsResponse, error) + // ConnectTarget connects to an iSCSI Target + ConnectTarget(ctx context.Context, in *ConnectTargetRequest, opts ...grpc.CallOption) (*ConnectTargetResponse, error) + // DisconnectTarget disconnects from an iSCSI Target + DisconnectTarget(ctx context.Context, in *DisconnectTargetRequest, opts ...grpc.CallOption) (*DisconnectTargetResponse, error) + // GetTargetDisks returns the disk addresses that correspond to an iSCSI + // target + GetTargetDisks(ctx context.Context, in *GetTargetDisksRequest, opts ...grpc.CallOption) (*GetTargetDisksResponse, error) +} + +type iscsiClient struct { + cc grpc.ClientConnInterface +} + +func NewIscsiClient(cc grpc.ClientConnInterface) IscsiClient { + return &iscsiClient{cc} +} + +func (c *iscsiClient) AddTargetPortal(ctx context.Context, in *AddTargetPortalRequest, opts ...grpc.CallOption) (*AddTargetPortalResponse, error) { + out := new(AddTargetPortalResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/AddTargetPortal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) DiscoverTargetPortal(ctx context.Context, in *DiscoverTargetPortalRequest, opts ...grpc.CallOption) (*DiscoverTargetPortalResponse, error) { + out := new(DiscoverTargetPortalResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/DiscoverTargetPortal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) RemoveTargetPortal(ctx context.Context, in *RemoveTargetPortalRequest, opts ...grpc.CallOption) (*RemoveTargetPortalResponse, error) { + out := new(RemoveTargetPortalResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/RemoveTargetPortal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) ListTargetPortals(ctx context.Context, in *ListTargetPortalsRequest, opts ...grpc.CallOption) (*ListTargetPortalsResponse, error) { + out := new(ListTargetPortalsResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/ListTargetPortals", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) ConnectTarget(ctx context.Context, in *ConnectTargetRequest, opts ...grpc.CallOption) (*ConnectTargetResponse, error) { + out := new(ConnectTargetResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/ConnectTarget", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) DisconnectTarget(ctx context.Context, in *DisconnectTargetRequest, opts ...grpc.CallOption) (*DisconnectTargetResponse, error) { + out := new(DisconnectTargetResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/DisconnectTarget", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *iscsiClient) GetTargetDisks(ctx context.Context, in *GetTargetDisksRequest, opts ...grpc.CallOption) (*GetTargetDisksResponse, error) { + out := new(GetTargetDisksResponse) + err := c.cc.Invoke(ctx, "/v1alpha1.Iscsi/GetTargetDisks", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// IscsiServer is the server API for Iscsi service. +type IscsiServer interface { + // AddTargetPortal registers an iSCSI target network address for later + // discovery. + // AddTargetPortal currently does not support selecting different NICs or + // a different iSCSI initiator (e.g a hardware initiator). This means that + // Windows will select the initiator NIC and instance on its own. + AddTargetPortal(context.Context, *AddTargetPortalRequest) (*AddTargetPortalResponse, error) + // DiscoverTargetPortal initiates discovery on an iSCSI target network address + // and returns discovered IQNs. + DiscoverTargetPortal(context.Context, *DiscoverTargetPortalRequest) (*DiscoverTargetPortalResponse, error) + // RemoveTargetPortal removes an iSCSI target network address registration. + RemoveTargetPortal(context.Context, *RemoveTargetPortalRequest) (*RemoveTargetPortalResponse, error) + // ListTargetPortal lists all currently registered iSCSI target network + // addresses. + ListTargetPortals(context.Context, *ListTargetPortalsRequest) (*ListTargetPortalsResponse, error) + // ConnectTarget connects to an iSCSI Target + ConnectTarget(context.Context, *ConnectTargetRequest) (*ConnectTargetResponse, error) + // DisconnectTarget disconnects from an iSCSI Target + DisconnectTarget(context.Context, *DisconnectTargetRequest) (*DisconnectTargetResponse, error) + // GetTargetDisks returns the disk addresses that correspond to an iSCSI + // target + GetTargetDisks(context.Context, *GetTargetDisksRequest) (*GetTargetDisksResponse, error) +} + +// UnimplementedIscsiServer can be embedded to have forward compatible implementations. +type UnimplementedIscsiServer struct { +} + +func (*UnimplementedIscsiServer) AddTargetPortal(ctx context.Context, req *AddTargetPortalRequest) (*AddTargetPortalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddTargetPortal not implemented") +} +func (*UnimplementedIscsiServer) DiscoverTargetPortal(ctx context.Context, req *DiscoverTargetPortalRequest) (*DiscoverTargetPortalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DiscoverTargetPortal not implemented") +} +func (*UnimplementedIscsiServer) RemoveTargetPortal(ctx context.Context, req *RemoveTargetPortalRequest) (*RemoveTargetPortalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveTargetPortal not implemented") +} +func (*UnimplementedIscsiServer) ListTargetPortals(ctx context.Context, req *ListTargetPortalsRequest) (*ListTargetPortalsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListTargetPortals not implemented") +} +func (*UnimplementedIscsiServer) ConnectTarget(ctx context.Context, req *ConnectTargetRequest) (*ConnectTargetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConnectTarget not implemented") +} +func (*UnimplementedIscsiServer) DisconnectTarget(ctx context.Context, req *DisconnectTargetRequest) (*DisconnectTargetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DisconnectTarget not implemented") +} +func (*UnimplementedIscsiServer) GetTargetDisks(ctx context.Context, req *GetTargetDisksRequest) (*GetTargetDisksResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTargetDisks not implemented") +} + +func RegisterIscsiServer(s *grpc.Server, srv IscsiServer) { + s.RegisterService(&_Iscsi_serviceDesc, srv) +} + +func _Iscsi_AddTargetPortal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddTargetPortalRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).AddTargetPortal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/AddTargetPortal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).AddTargetPortal(ctx, req.(*AddTargetPortalRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_DiscoverTargetPortal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DiscoverTargetPortalRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).DiscoverTargetPortal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/DiscoverTargetPortal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).DiscoverTargetPortal(ctx, req.(*DiscoverTargetPortalRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_RemoveTargetPortal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveTargetPortalRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).RemoveTargetPortal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/RemoveTargetPortal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).RemoveTargetPortal(ctx, req.(*RemoveTargetPortalRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_ListTargetPortals_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListTargetPortalsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).ListTargetPortals(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/ListTargetPortals", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).ListTargetPortals(ctx, req.(*ListTargetPortalsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_ConnectTarget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ConnectTargetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).ConnectTarget(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/ConnectTarget", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).ConnectTarget(ctx, req.(*ConnectTargetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_DisconnectTarget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DisconnectTargetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).DisconnectTarget(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/DisconnectTarget", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).DisconnectTarget(ctx, req.(*DisconnectTargetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Iscsi_GetTargetDisks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTargetDisksRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IscsiServer).GetTargetDisks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1alpha1.Iscsi/GetTargetDisks", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IscsiServer).GetTargetDisks(ctx, req.(*GetTargetDisksRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Iscsi_serviceDesc = grpc.ServiceDesc{ + ServiceName: "v1alpha1.Iscsi", + HandlerType: (*IscsiServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddTargetPortal", + Handler: _Iscsi_AddTargetPortal_Handler, + }, + { + MethodName: "DiscoverTargetPortal", + Handler: _Iscsi_DiscoverTargetPortal_Handler, + }, + { + MethodName: "RemoveTargetPortal", + Handler: _Iscsi_RemoveTargetPortal_Handler, + }, + { + MethodName: "ListTargetPortals", + Handler: _Iscsi_ListTargetPortals_Handler, + }, + { + MethodName: "ConnectTarget", + Handler: _Iscsi_ConnectTarget_Handler, + }, + { + MethodName: "DisconnectTarget", + Handler: _Iscsi_DisconnectTarget_Handler, + }, + { + MethodName: "GetTargetDisks", + Handler: _Iscsi_GetTargetDisks_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto", +} diff --git a/vendor/github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto b/vendor/github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto new file mode 100644 index 00000000..b667f8da --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1/api.proto @@ -0,0 +1,153 @@ +syntax = "proto3"; + +package v1alpha1; + +option go_package = "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1"; + +service Iscsi { + // AddTargetPortal registers an iSCSI target network address for later + // discovery. + // AddTargetPortal currently does not support selecting different NICs or + // a different iSCSI initiator (e.g a hardware initiator). This means that + // Windows will select the initiator NIC and instance on its own. + rpc AddTargetPortal(AddTargetPortalRequest) + returns (AddTargetPortalResponse) {} + + // DiscoverTargetPortal initiates discovery on an iSCSI target network address + // and returns discovered IQNs. + rpc DiscoverTargetPortal(DiscoverTargetPortalRequest) + returns (DiscoverTargetPortalResponse) {} + + // RemoveTargetPortal removes an iSCSI target network address registration. + rpc RemoveTargetPortal(RemoveTargetPortalRequest) + returns (RemoveTargetPortalResponse) {} + + // ListTargetPortal lists all currently registered iSCSI target network + // addresses. + rpc ListTargetPortals(ListTargetPortalsRequest) + returns (ListTargetPortalsResponse) {} + + // ConnectTarget connects to an iSCSI Target + rpc ConnectTarget(ConnectTargetRequest) returns (ConnectTargetResponse) {} + + // DisconnectTarget disconnects from an iSCSI Target + rpc DisconnectTarget(DisconnectTargetRequest) + returns (DisconnectTargetResponse) {} + + // GetTargetDisks returns the disk addresses that correspond to an iSCSI + // target + rpc GetTargetDisks(GetTargetDisksRequest) returns (GetTargetDisksResponse) {} +} + +// TargetPortal is an address and port pair for a specific iSCSI storage +// target. +message TargetPortal { + // iSCSI Target (server) address + string target_address = 1; + + // iSCSI Target port (default iSCSI port is 3260) + uint32 target_port = 2; +} + +message AddTargetPortalRequest { + // iSCSI Target Portal to register in the initiator + TargetPortal target_portal = 1; +} + +message AddTargetPortalResponse { + // Intentionally empty +} + +message DiscoverTargetPortalRequest { + // iSCSI Target Portal on which to initiate discovery + TargetPortal target_portal = 1; +} + +message DiscoverTargetPortalResponse { + // List of discovered IQN addresses + // follows IQN format: iqn.yyyy-mm.naming-authority:unique-name + repeated string iqns = 1; +} + +message RemoveTargetPortalRequest { + // iSCSI Target Portal + TargetPortal target_portal = 1; +} + +message RemoveTargetPortalResponse { + // Intentionally empty +} + +message ListTargetPortalsRequest { + // Intentionally empty +} + +message ListTargetPortalsResponse { + // A list of Target Portals currently registered in the initiator + repeated TargetPortal target_portals = 1; +} + +enum AuthenticationType { + // No authentication is used + NONE = 0; + + // One way CHAP authentication. The target authenticates the initiator. + ONE_WAY_CHAP = 1; + + // Mutual CHAP authentication. The target and initiator authenticate each + // other. + MUTUAL_CHAP = 2; +} + +message ConnectTargetRequest { + // Target portal to which the initiator will connect + TargetPortal target_portal = 1; + + // IQN of the iSCSI Target + string iqn = 2; + + // Connection authentication type, None by default + // + // One Way Chap uses the chap_username and chap_secret + // fields mentioned below to authenticate the initiator. + // + // Mutual Chap uses both the user/secret mentioned below + // and the Initiator Chap Secret to authenticate the target and initiator. + AuthenticationType auth_type = 3; + + // CHAP Username used to authenticate the initiator + string chap_username = 4; + + // CHAP password used to authenticate the initiator + string chap_secret = 5; +} + +message ConnectTargetResponse { + // Intentionally empty +} + +message GetTargetDisksRequest { + // Target portal whose disks will be queried + TargetPortal target_portal = 1; + + // IQN of the iSCSI Target + string iqn = 2; +} + +message GetTargetDisksResponse { + // List composed of disk ids (numbers) that are associated with the + // iSCSI target + repeated string diskIDs = 1; +} + +message DisconnectTargetRequest { + // Target portal from which initiator will disconnect + TargetPortal target_portal = 1; + + // IQN of the iSCSI Target + string iqn = 2; +} + +message DisconnectTargetResponse { + // Intentionally empty +} diff --git a/vendor/github.com/kubernetes-csi/csi-proxy/client/groups/iscsi/v1alpha1/client_generated.go b/vendor/github.com/kubernetes-csi/csi-proxy/client/groups/iscsi/v1alpha1/client_generated.go new file mode 100644 index 00000000..d4e75b61 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-proxy/client/groups/iscsi/v1alpha1/client_generated.go @@ -0,0 +1,80 @@ +// Code generated by csi-proxy-api-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "net" + + "github.com/Microsoft/go-winio" + "github.com/kubernetes-csi/csi-proxy/client" + "github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1" + "github.com/kubernetes-csi/csi-proxy/client/apiversion" + "google.golang.org/grpc" +) + +const groupName = "iscsi" + +var version = apiversion.NewVersionOrPanic("v1alpha1") + +type Client struct { + client v1alpha1.IscsiClient + connection *grpc.ClientConn +} + +// NewClient returns a client to make calls to the iscsi API group version v1alpha1. +// It's the caller's responsibility to Close the client when done. +func NewClient() (*Client, error) { + pipePath := client.PipePath(groupName, version) + + connection, err := grpc.Dial(pipePath, + grpc.WithContextDialer(func(context context.Context, s string) (net.Conn, error) { + return winio.DialPipeContext(context, s) + }), + grpc.WithInsecure()) + if err != nil { + return nil, err + } + + client := v1alpha1.NewIscsiClient(connection) + return &Client{ + client: client, + connection: connection, + }, nil +} + +// Close closes the client. It must be called before the client gets GC-ed. +func (w *Client) Close() error { + return w.connection.Close() +} + +// ensures we implement all the required methods +var _ v1alpha1.IscsiClient = &Client{} + +func (w *Client) AddTargetPortal(context context.Context, request *v1alpha1.AddTargetPortalRequest, opts ...grpc.CallOption) (*v1alpha1.AddTargetPortalResponse, error) { + return w.client.AddTargetPortal(context, request, opts...) +} + +func (w *Client) ConnectTarget(context context.Context, request *v1alpha1.ConnectTargetRequest, opts ...grpc.CallOption) (*v1alpha1.ConnectTargetResponse, error) { + return w.client.ConnectTarget(context, request, opts...) +} + +func (w *Client) DisconnectTarget(context context.Context, request *v1alpha1.DisconnectTargetRequest, opts ...grpc.CallOption) (*v1alpha1.DisconnectTargetResponse, error) { + return w.client.DisconnectTarget(context, request, opts...) +} + +func (w *Client) DiscoverTargetPortal(context context.Context, request *v1alpha1.DiscoverTargetPortalRequest, opts ...grpc.CallOption) (*v1alpha1.DiscoverTargetPortalResponse, error) { + return w.client.DiscoverTargetPortal(context, request, opts...) +} + +func (w *Client) GetTargetDisks(context context.Context, request *v1alpha1.GetTargetDisksRequest, opts ...grpc.CallOption) (*v1alpha1.GetTargetDisksResponse, error) { + return w.client.GetTargetDisks(context, request, opts...) +} + +func (w *Client) ListTargetPortals(context context.Context, request *v1alpha1.ListTargetPortalsRequest, opts ...grpc.CallOption) (*v1alpha1.ListTargetPortalsResponse, error) { + return w.client.ListTargetPortals(context, request, opts...) +} + +func (w *Client) RemoveTargetPortal(context context.Context, request *v1alpha1.RemoveTargetPortalRequest, opts ...grpc.CallOption) (*v1alpha1.RemoveTargetPortalResponse, error) { + return w.client.RemoveTargetPortal(context, request, opts...) +} diff --git a/vendor/golang.org/x/xerrors/LICENSE b/vendor/golang.org/x/xerrors/LICENSE new file mode 100644 index 00000000..e4a47e17 --- /dev/null +++ b/vendor/golang.org/x/xerrors/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2019 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/xerrors/PATENTS b/vendor/golang.org/x/xerrors/PATENTS new file mode 100644 index 00000000..73309904 --- /dev/null +++ b/vendor/golang.org/x/xerrors/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/xerrors/README b/vendor/golang.org/x/xerrors/README new file mode 100644 index 00000000..aac7867a --- /dev/null +++ b/vendor/golang.org/x/xerrors/README @@ -0,0 +1,2 @@ +This repository holds the transition packages for the new Go 1.13 error values. +See golang.org/design/29934-error-values. diff --git a/vendor/golang.org/x/xerrors/adaptor.go b/vendor/golang.org/x/xerrors/adaptor.go new file mode 100644 index 00000000..4317f248 --- /dev/null +++ b/vendor/golang.org/x/xerrors/adaptor.go @@ -0,0 +1,193 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "bytes" + "fmt" + "io" + "reflect" + "strconv" +) + +// FormatError calls the FormatError method of f with an errors.Printer +// configured according to s and verb, and writes the result to s. +func FormatError(f Formatter, s fmt.State, verb rune) { + // Assuming this function is only called from the Format method, and given + // that FormatError takes precedence over Format, it cannot be called from + // any package that supports errors.Formatter. It is therefore safe to + // disregard that State may be a specific printer implementation and use one + // of our choice instead. + + // limitations: does not support printing error as Go struct. + + var ( + sep = " " // separator before next error + p = &state{State: s} + direct = true + ) + + var err error = f + + switch verb { + // Note that this switch must match the preference order + // for ordinary string printing (%#v before %+v, and so on). + + case 'v': + if s.Flag('#') { + if stringer, ok := err.(fmt.GoStringer); ok { + io.WriteString(&p.buf, stringer.GoString()) + goto exit + } + // proceed as if it were %v + } else if s.Flag('+') { + p.printDetail = true + sep = "\n - " + } + case 's': + case 'q', 'x', 'X': + // Use an intermediate buffer in the rare cases that precision, + // truncation, or one of the alternative verbs (q, x, and X) are + // specified. + direct = false + + default: + p.buf.WriteString("%!") + p.buf.WriteRune(verb) + p.buf.WriteByte('(') + switch { + case err != nil: + p.buf.WriteString(reflect.TypeOf(f).String()) + default: + p.buf.WriteString("") + } + p.buf.WriteByte(')') + io.Copy(s, &p.buf) + return + } + +loop: + for { + switch v := err.(type) { + case Formatter: + err = v.FormatError((*printer)(p)) + case fmt.Formatter: + v.Format(p, 'v') + break loop + default: + io.WriteString(&p.buf, v.Error()) + break loop + } + if err == nil { + break + } + if p.needColon || !p.printDetail { + p.buf.WriteByte(':') + p.needColon = false + } + p.buf.WriteString(sep) + p.inDetail = false + p.needNewline = false + } + +exit: + width, okW := s.Width() + prec, okP := s.Precision() + + if !direct || (okW && width > 0) || okP { + // Construct format string from State s. + format := []byte{'%'} + if s.Flag('-') { + format = append(format, '-') + } + if s.Flag('+') { + format = append(format, '+') + } + if s.Flag(' ') { + format = append(format, ' ') + } + if okW { + format = strconv.AppendInt(format, int64(width), 10) + } + if okP { + format = append(format, '.') + format = strconv.AppendInt(format, int64(prec), 10) + } + format = append(format, string(verb)...) + fmt.Fprintf(s, string(format), p.buf.String()) + } else { + io.Copy(s, &p.buf) + } +} + +var detailSep = []byte("\n ") + +// state tracks error printing state. It implements fmt.State. +type state struct { + fmt.State + buf bytes.Buffer + + printDetail bool + inDetail bool + needColon bool + needNewline bool +} + +func (s *state) Write(b []byte) (n int, err error) { + if s.printDetail { + if len(b) == 0 { + return 0, nil + } + if s.inDetail && s.needColon { + s.needNewline = true + if b[0] == '\n' { + b = b[1:] + } + } + k := 0 + for i, c := range b { + if s.needNewline { + if s.inDetail && s.needColon { + s.buf.WriteByte(':') + s.needColon = false + } + s.buf.Write(detailSep) + s.needNewline = false + } + if c == '\n' { + s.buf.Write(b[k:i]) + k = i + 1 + s.needNewline = true + } + } + s.buf.Write(b[k:]) + if !s.inDetail { + s.needColon = true + } + } else if !s.inDetail { + s.buf.Write(b) + } + return len(b), nil +} + +// printer wraps a state to implement an xerrors.Printer. +type printer state + +func (s *printer) Print(args ...interface{}) { + if !s.inDetail || s.printDetail { + fmt.Fprint((*state)(s), args...) + } +} + +func (s *printer) Printf(format string, args ...interface{}) { + if !s.inDetail || s.printDetail { + fmt.Fprintf((*state)(s), format, args...) + } +} + +func (s *printer) Detail() bool { + s.inDetail = true + return s.printDetail +} diff --git a/vendor/golang.org/x/xerrors/codereview.cfg b/vendor/golang.org/x/xerrors/codereview.cfg new file mode 100644 index 00000000..3f8b14b6 --- /dev/null +++ b/vendor/golang.org/x/xerrors/codereview.cfg @@ -0,0 +1 @@ +issuerepo: golang/go diff --git a/vendor/golang.org/x/xerrors/doc.go b/vendor/golang.org/x/xerrors/doc.go new file mode 100644 index 00000000..eef99d9d --- /dev/null +++ b/vendor/golang.org/x/xerrors/doc.go @@ -0,0 +1,22 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package xerrors implements functions to manipulate errors. +// +// This package is based on the Go 2 proposal for error values: +// https://golang.org/design/29934-error-values +// +// These functions were incorporated into the standard library's errors package +// in Go 1.13: +// - Is +// - As +// - Unwrap +// +// Also, Errorf's %w verb was incorporated into fmt.Errorf. +// +// Use this package to get equivalent behavior in all supported Go versions. +// +// No other features of this package were included in Go 1.13, and at present +// there are no plans to include any of them. +package xerrors // import "golang.org/x/xerrors" diff --git a/vendor/golang.org/x/xerrors/errors.go b/vendor/golang.org/x/xerrors/errors.go new file mode 100644 index 00000000..e88d3772 --- /dev/null +++ b/vendor/golang.org/x/xerrors/errors.go @@ -0,0 +1,33 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import "fmt" + +// errorString is a trivial implementation of error. +type errorString struct { + s string + frame Frame +} + +// New returns an error that formats as the given text. +// +// The returned error contains a Frame set to the caller's location and +// implements Formatter to show this information when printed with details. +func New(text string) error { + return &errorString{text, Caller(1)} +} + +func (e *errorString) Error() string { + return e.s +} + +func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) } + +func (e *errorString) FormatError(p Printer) (next error) { + p.Print(e.s) + e.frame.Format(p) + return nil +} diff --git a/vendor/golang.org/x/xerrors/fmt.go b/vendor/golang.org/x/xerrors/fmt.go new file mode 100644 index 00000000..829862dd --- /dev/null +++ b/vendor/golang.org/x/xerrors/fmt.go @@ -0,0 +1,187 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "fmt" + "strings" + "unicode" + "unicode/utf8" + + "golang.org/x/xerrors/internal" +) + +const percentBangString = "%!" + +// Errorf formats according to a format specifier and returns the string as a +// value that satisfies error. +// +// The returned error includes the file and line number of the caller when +// formatted with additional detail enabled. If the last argument is an error +// the returned error's Format method will return it if the format string ends +// with ": %s", ": %v", or ": %w". If the last argument is an error and the +// format string ends with ": %w", the returned error implements an Unwrap +// method returning it. +// +// If the format specifier includes a %w verb with an error operand in a +// position other than at the end, the returned error will still implement an +// Unwrap method returning the operand, but the error's Format method will not +// return the wrapped error. +// +// It is invalid to include more than one %w verb or to supply it with an +// operand that does not implement the error interface. The %w verb is otherwise +// a synonym for %v. +func Errorf(format string, a ...interface{}) error { + format = formatPlusW(format) + // Support a ": %[wsv]" suffix, which works well with xerrors.Formatter. + wrap := strings.HasSuffix(format, ": %w") + idx, format2, ok := parsePercentW(format) + percentWElsewhere := !wrap && idx >= 0 + if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) { + err := errorAt(a, len(a)-1) + if err == nil { + return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)} + } + // TODO: this is not entirely correct. The error value could be + // printed elsewhere in format if it mixes numbered with unnumbered + // substitutions. With relatively small changes to doPrintf we can + // have it optionally ignore extra arguments and pass the argument + // list in its entirety. + msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...) + frame := Frame{} + if internal.EnableTrace { + frame = Caller(1) + } + if wrap { + return &wrapError{msg, err, frame} + } + return &noWrapError{msg, err, frame} + } + // Support %w anywhere. + // TODO: don't repeat the wrapped error's message when %w occurs in the middle. + msg := fmt.Sprintf(format2, a...) + if idx < 0 { + return &noWrapError{msg, nil, Caller(1)} + } + err := errorAt(a, idx) + if !ok || err == nil { + // Too many %ws or argument of %w is not an error. Approximate the Go + // 1.13 fmt.Errorf message. + return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)} + } + frame := Frame{} + if internal.EnableTrace { + frame = Caller(1) + } + return &wrapError{msg, err, frame} +} + +func errorAt(args []interface{}, i int) error { + if i < 0 || i >= len(args) { + return nil + } + err, ok := args[i].(error) + if !ok { + return nil + } + return err +} + +// formatPlusW is used to avoid the vet check that will barf at %w. +func formatPlusW(s string) string { + return s +} + +// Return the index of the only %w in format, or -1 if none. +// Also return a rewritten format string with %w replaced by %v, and +// false if there is more than one %w. +// TODO: handle "%[N]w". +func parsePercentW(format string) (idx int, newFormat string, ok bool) { + // Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go. + idx = -1 + ok = true + n := 0 + sz := 0 + var isW bool + for i := 0; i < len(format); i += sz { + if format[i] != '%' { + sz = 1 + continue + } + // "%%" is not a format directive. + if i+1 < len(format) && format[i+1] == '%' { + sz = 2 + continue + } + sz, isW = parsePrintfVerb(format[i:]) + if isW { + if idx >= 0 { + ok = false + } else { + idx = n + } + // "Replace" the last character, the 'w', with a 'v'. + p := i + sz - 1 + format = format[:p] + "v" + format[p+1:] + } + n++ + } + return idx, format, ok +} + +// Parse the printf verb starting with a % at s[0]. +// Return how many bytes it occupies and whether the verb is 'w'. +func parsePrintfVerb(s string) (int, bool) { + // Assume only that the directive is a sequence of non-letters followed by a single letter. + sz := 0 + var r rune + for i := 1; i < len(s); i += sz { + r, sz = utf8.DecodeRuneInString(s[i:]) + if unicode.IsLetter(r) { + return i + sz, r == 'w' + } + } + return len(s), false +} + +type noWrapError struct { + msg string + err error + frame Frame +} + +func (e *noWrapError) Error() string { + return fmt.Sprint(e) +} + +func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) } + +func (e *noWrapError) FormatError(p Printer) (next error) { + p.Print(e.msg) + e.frame.Format(p) + return e.err +} + +type wrapError struct { + msg string + err error + frame Frame +} + +func (e *wrapError) Error() string { + return fmt.Sprint(e) +} + +func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) } + +func (e *wrapError) FormatError(p Printer) (next error) { + p.Print(e.msg) + e.frame.Format(p) + return e.err +} + +func (e *wrapError) Unwrap() error { + return e.err +} diff --git a/vendor/golang.org/x/xerrors/format.go b/vendor/golang.org/x/xerrors/format.go new file mode 100644 index 00000000..1bc9c26b --- /dev/null +++ b/vendor/golang.org/x/xerrors/format.go @@ -0,0 +1,34 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +// A Formatter formats error messages. +type Formatter interface { + error + + // FormatError prints the receiver's first error and returns the next error in + // the error chain, if any. + FormatError(p Printer) (next error) +} + +// A Printer formats error messages. +// +// The most common implementation of Printer is the one provided by package fmt +// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message +// typically provide their own implementations. +type Printer interface { + // Print appends args to the message output. + Print(args ...interface{}) + + // Printf writes a formatted string. + Printf(format string, args ...interface{}) + + // Detail reports whether error detail is requested. + // After the first call to Detail, all text written to the Printer + // is formatted as additional detail, or ignored when + // detail has not been requested. + // If Detail returns false, the caller can avoid printing the detail at all. + Detail() bool +} diff --git a/vendor/golang.org/x/xerrors/frame.go b/vendor/golang.org/x/xerrors/frame.go new file mode 100644 index 00000000..0de628ec --- /dev/null +++ b/vendor/golang.org/x/xerrors/frame.go @@ -0,0 +1,56 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "runtime" +) + +// A Frame contains part of a call stack. +type Frame struct { + // Make room for three PCs: the one we were asked for, what it called, + // and possibly a PC for skipPleaseUseCallersFrames. See: + // https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169 + frames [3]uintptr +} + +// Caller returns a Frame that describes a frame on the caller's stack. +// The argument skip is the number of frames to skip over. +// Caller(0) returns the frame for the caller of Caller. +func Caller(skip int) Frame { + var s Frame + runtime.Callers(skip+1, s.frames[:]) + return s +} + +// location reports the file, line, and function of a frame. +// +// The returned function may be "" even if file and line are not. +func (f Frame) location() (function, file string, line int) { + frames := runtime.CallersFrames(f.frames[:]) + if _, ok := frames.Next(); !ok { + return "", "", 0 + } + fr, ok := frames.Next() + if !ok { + return "", "", 0 + } + return fr.Function, fr.File, fr.Line +} + +// Format prints the stack as error detail. +// It should be called from an error's Format implementation +// after printing any other error detail. +func (f Frame) Format(p Printer) { + if p.Detail() { + function, file, line := f.location() + if function != "" { + p.Printf("%s\n ", function) + } + if file != "" { + p.Printf("%s:%d\n", file, line) + } + } +} diff --git a/vendor/golang.org/x/xerrors/go.mod b/vendor/golang.org/x/xerrors/go.mod new file mode 100644 index 00000000..870d4f61 --- /dev/null +++ b/vendor/golang.org/x/xerrors/go.mod @@ -0,0 +1,3 @@ +module golang.org/x/xerrors + +go 1.11 diff --git a/vendor/golang.org/x/xerrors/internal/internal.go b/vendor/golang.org/x/xerrors/internal/internal.go new file mode 100644 index 00000000..89f4eca5 --- /dev/null +++ b/vendor/golang.org/x/xerrors/internal/internal.go @@ -0,0 +1,8 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +// EnableTrace indicates whether stack information should be recorded in errors. +var EnableTrace = true diff --git a/vendor/golang.org/x/xerrors/wrap.go b/vendor/golang.org/x/xerrors/wrap.go new file mode 100644 index 00000000..9a3b5103 --- /dev/null +++ b/vendor/golang.org/x/xerrors/wrap.go @@ -0,0 +1,106 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "reflect" +) + +// A Wrapper provides context around another error. +type Wrapper interface { + // Unwrap returns the next error in the error chain. + // If there is no next error, Unwrap returns nil. + Unwrap() error +} + +// Opaque returns an error with the same error formatting as err +// but that does not match err and cannot be unwrapped. +func Opaque(err error) error { + return noWrapper{err} +} + +type noWrapper struct { + error +} + +func (e noWrapper) FormatError(p Printer) (next error) { + if f, ok := e.error.(Formatter); ok { + return f.FormatError(p) + } + p.Print(e.error) + return nil +} + +// Unwrap returns the result of calling the Unwrap method on err, if err implements +// Unwrap. Otherwise, Unwrap returns nil. +func Unwrap(err error) error { + u, ok := err.(Wrapper) + if !ok { + return nil + } + return u.Unwrap() +} + +// Is reports whether any error in err's chain matches target. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err, target error) bool { + if target == nil { + return err == target + } + + isComparable := reflect.TypeOf(target).Comparable() + for { + if isComparable && err == target { + return true + } + if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { + return true + } + // TODO: consider supporing target.Is(err). This would allow + // user-definable predicates, but also may allow for coping with sloppy + // APIs, thereby making it easier to get away with them. + if err = Unwrap(err); err == nil { + return false + } + } +} + +// As finds the first error in err's chain that matches the type to which target +// points, and if so, sets the target to its value and returns true. An error +// matches a type if it is assignable to the target type, or if it has a method +// As(interface{}) bool such that As(target) returns true. As will panic if target +// is not a non-nil pointer to a type which implements error or is of interface type. +// +// The As method should set the target to its value and return true if err +// matches the type to which target points. +func As(err error, target interface{}) bool { + if target == nil { + panic("errors: target cannot be nil") + } + val := reflect.ValueOf(target) + typ := val.Type() + if typ.Kind() != reflect.Ptr || val.IsNil() { + panic("errors: target must be a non-nil pointer") + } + if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) { + panic("errors: *target must be interface or implement error") + } + targetType := typ.Elem() + for err != nil { + if reflect.TypeOf(err).AssignableTo(targetType) { + val.Elem().Set(reflect.ValueOf(err)) + return true + } + if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) { + return true + } + err = Unwrap(err) + } + return false +} + +var errorType = reflect.TypeOf((*error)(nil)).Elem() diff --git a/vendor/google.golang.org/protobuf/internal/msgfmt/format.go b/vendor/google.golang.org/protobuf/internal/msgfmt/format.go new file mode 100644 index 00000000..9547a530 --- /dev/null +++ b/vendor/google.golang.org/protobuf/internal/msgfmt/format.go @@ -0,0 +1,275 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package msgfmt implements a text marshaler combining the desirable features +// of both the JSON and proto text formats. +// It is optimized for human readability and has no associated deserializer. +package msgfmt + +import ( + "bytes" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "google.golang.org/protobuf/encoding/protowire" + "google.golang.org/protobuf/internal/detrand" + "google.golang.org/protobuf/internal/genid" + "google.golang.org/protobuf/internal/mapsort" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +// Format returns a formatted string for the message. +func Format(m proto.Message) string { + return string(appendMessage(nil, m.ProtoReflect())) +} + +func appendValue(b []byte, v protoreflect.Value, fd protoreflect.FieldDescriptor) []byte { + switch v := v.Interface().(type) { + case bool, int32, int64, uint32, uint64, float32, float64: + return append(b, fmt.Sprint(v)...) + case string: + return append(b, strconv.Quote(string(v))...) + case []byte: + return append(b, strconv.Quote(string(v))...) + case protoreflect.EnumNumber: + return appendEnum(b, v, fd.Enum()) + case protoreflect.Message: + return appendMessage(b, v) + case protoreflect.List: + return appendList(b, v, fd) + case protoreflect.Map: + return appendMap(b, v, fd) + default: + panic(fmt.Sprintf("invalid type: %T", v)) + } +} + +func appendEnum(b []byte, v protoreflect.EnumNumber, ed protoreflect.EnumDescriptor) []byte { + if ev := ed.Values().ByNumber(v); ev != nil { + return append(b, ev.Name()...) + } + return strconv.AppendInt(b, int64(v), 10) +} + +func appendMessage(b []byte, m protoreflect.Message) []byte { + if b2 := appendKnownMessage(b, m); b2 != nil { + return b2 + } + + var fds []protoreflect.FieldDescriptor + m.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool { + fds = append(fds, fd) + return true + }) + sort.Slice(fds, func(i, j int) bool { + fdi, fdj := fds[i], fds[j] + switch { + case !fdi.IsExtension() && !fdj.IsExtension(): + return fdi.Index() < fdj.Index() + case fdi.IsExtension() && fdj.IsExtension(): + return fdi.FullName() < fdj.FullName() + default: + return !fdi.IsExtension() && fdj.IsExtension() + } + }) + + b = append(b, '{') + for _, fd := range fds { + k := string(fd.Name()) + if fd.IsExtension() { + k = string("[" + fd.FullName() + "]") + } + + b = append(b, k...) + b = append(b, ':') + b = appendValue(b, m.Get(fd), fd) + b = append(b, delim()...) + } + b = appendUnknown(b, m.GetUnknown()) + b = bytes.TrimRight(b, delim()) + b = append(b, '}') + return b +} + +var protocmpMessageType = reflect.TypeOf(map[string]interface{}(nil)) + +func appendKnownMessage(b []byte, m protoreflect.Message) []byte { + md := m.Descriptor() + fds := md.Fields() + switch md.FullName() { + case genid.Any_message_fullname: + var msgVal protoreflect.Message + url := m.Get(fds.ByNumber(genid.Any_TypeUrl_field_number)).String() + if v := reflect.ValueOf(m); v.Type().ConvertibleTo(protocmpMessageType) { + // For protocmp.Message, directly obtain the sub-message value + // which is stored in structured form, rather than as raw bytes. + m2 := v.Convert(protocmpMessageType).Interface().(map[string]interface{}) + v, ok := m2[string(genid.Any_Value_field_name)].(proto.Message) + if !ok { + return nil + } + msgVal = v.ProtoReflect() + } else { + val := m.Get(fds.ByNumber(genid.Any_Value_field_number)).Bytes() + mt, err := protoregistry.GlobalTypes.FindMessageByURL(url) + if err != nil { + return nil + } + msgVal = mt.New() + err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(val, msgVal.Interface()) + if err != nil { + return nil + } + } + + b = append(b, '{') + b = append(b, "["+url+"]"...) + b = append(b, ':') + b = appendMessage(b, msgVal) + b = append(b, '}') + return b + + case genid.Timestamp_message_fullname: + secs := m.Get(fds.ByNumber(genid.Timestamp_Seconds_field_number)).Int() + nanos := m.Get(fds.ByNumber(genid.Timestamp_Nanos_field_number)).Int() + if nanos < 0 || nanos >= 1e9 { + return nil + } + t := time.Unix(secs, nanos).UTC() + x := t.Format("2006-01-02T15:04:05.000000000") // RFC 3339 + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") + return append(b, x+"Z"...) + + case genid.Duration_message_fullname: + secs := m.Get(fds.ByNumber(genid.Duration_Seconds_field_number)).Int() + nanos := m.Get(fds.ByNumber(genid.Duration_Nanos_field_number)).Int() + if nanos <= -1e9 || nanos >= 1e9 || (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) { + return nil + } + x := fmt.Sprintf("%d.%09d", secs, int64(math.Abs(float64(nanos)))) + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") + return append(b, x+"s"...) + + case genid.BoolValue_message_fullname, + genid.Int32Value_message_fullname, + genid.Int64Value_message_fullname, + genid.UInt32Value_message_fullname, + genid.UInt64Value_message_fullname, + genid.FloatValue_message_fullname, + genid.DoubleValue_message_fullname, + genid.StringValue_message_fullname, + genid.BytesValue_message_fullname: + fd := fds.ByNumber(genid.WrapperValue_Value_field_number) + return appendValue(b, m.Get(fd), fd) + } + + return nil +} + +func appendUnknown(b []byte, raw protoreflect.RawFields) []byte { + rs := make(map[protoreflect.FieldNumber][]protoreflect.RawFields) + for len(raw) > 0 { + num, _, n := protowire.ConsumeField(raw) + rs[num] = append(rs[num], raw[:n]) + raw = raw[n:] + } + + var ns []protoreflect.FieldNumber + for n := range rs { + ns = append(ns, n) + } + sort.Slice(ns, func(i, j int) bool { return ns[i] < ns[j] }) + + for _, n := range ns { + var leftBracket, rightBracket string + if len(rs[n]) > 1 { + leftBracket, rightBracket = "[", "]" + } + + b = strconv.AppendInt(b, int64(n), 10) + b = append(b, ':') + b = append(b, leftBracket...) + for _, r := range rs[n] { + num, typ, n := protowire.ConsumeTag(r) + r = r[n:] + switch typ { + case protowire.VarintType: + v, _ := protowire.ConsumeVarint(r) + b = strconv.AppendInt(b, int64(v), 10) + case protowire.Fixed32Type: + v, _ := protowire.ConsumeFixed32(r) + b = append(b, fmt.Sprintf("0x%08x", v)...) + case protowire.Fixed64Type: + v, _ := protowire.ConsumeFixed64(r) + b = append(b, fmt.Sprintf("0x%016x", v)...) + case protowire.BytesType: + v, _ := protowire.ConsumeBytes(r) + b = strconv.AppendQuote(b, string(v)) + case protowire.StartGroupType: + v, _ := protowire.ConsumeGroup(num, r) + b = append(b, '{') + b = appendUnknown(b, v) + b = bytes.TrimRight(b, delim()) + b = append(b, '}') + default: + panic(fmt.Sprintf("invalid type: %v", typ)) + } + b = append(b, delim()...) + } + b = bytes.TrimRight(b, delim()) + b = append(b, rightBracket...) + b = append(b, delim()...) + } + return b +} + +func appendList(b []byte, v protoreflect.List, fd protoreflect.FieldDescriptor) []byte { + b = append(b, '[') + for i := 0; i < v.Len(); i++ { + b = appendValue(b, v.Get(i), fd) + b = append(b, delim()...) + } + b = bytes.TrimRight(b, delim()) + b = append(b, ']') + return b +} + +func appendMap(b []byte, v protoreflect.Map, fd protoreflect.FieldDescriptor) []byte { + var ks []protoreflect.MapKey + mapsort.Range(v, fd.MapKey().Kind(), func(k protoreflect.MapKey, _ protoreflect.Value) bool { + ks = append(ks, k) + return true + }) + + b = append(b, '{') + for _, k := range ks { + b = appendValue(b, k.Value(), fd.MapKey()) + b = append(b, ':') + b = appendValue(b, v.Get(k), fd.MapValue()) + b = append(b, delim()...) + } + b = bytes.TrimRight(b, delim()) + b = append(b, '}') + return b +} + +func delim() string { + // Deliberately introduce instability into the message string to + // discourage users from depending on it. + if detrand.Bool() { + return " " + } + return ", " +} diff --git a/vendor/google.golang.org/protobuf/testing/protocmp/reflect.go b/vendor/google.golang.org/protobuf/testing/protocmp/reflect.go new file mode 100644 index 00000000..a4f9cac2 --- /dev/null +++ b/vendor/google.golang.org/protobuf/testing/protocmp/reflect.go @@ -0,0 +1,261 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protocmp + +import ( + "reflect" + "sort" + "strconv" + "strings" + + "google.golang.org/protobuf/internal/genid" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/runtime/protoiface" +) + +func reflectValueOf(v interface{}) protoreflect.Value { + switch v := v.(type) { + case Enum: + return protoreflect.ValueOfEnum(v.Number()) + case Message: + return protoreflect.ValueOfMessage(v.ProtoReflect()) + case []byte: + return protoreflect.ValueOfBytes(v) // avoid overlap with reflect.Slice check below + default: + switch rv := reflect.ValueOf(v); { + case rv.Kind() == reflect.Slice: + return protoreflect.ValueOfList(reflectList{rv}) + case rv.Kind() == reflect.Map: + return protoreflect.ValueOfMap(reflectMap{rv}) + default: + return protoreflect.ValueOf(v) + } + } +} + +type reflectMessage Message + +func (m reflectMessage) stringKey(fd protoreflect.FieldDescriptor) string { + if m.Descriptor() != fd.ContainingMessage() { + panic("mismatching containing message") + } + if fd.IsExtension() { + return string("[" + fd.FullName() + "]") + } + return string(fd.Name()) +} + +func (m reflectMessage) Descriptor() protoreflect.MessageDescriptor { + return (Message)(m).Descriptor() +} +func (m reflectMessage) Type() protoreflect.MessageType { + return reflectMessageType{m.Descriptor()} +} +func (m reflectMessage) New() protoreflect.Message { + return m.Type().New() +} +func (m reflectMessage) Interface() protoreflect.ProtoMessage { + return Message(m) +} +func (m reflectMessage) Range(f func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool) { + // Range over populated known fields. + fds := m.Descriptor().Fields() + for i := 0; i < fds.Len(); i++ { + fd := fds.Get(i) + if m.Has(fd) && !f(fd, m.Get(fd)) { + return + } + } + + // Range over populated extension fields. + for _, xd := range m[messageTypeKey].(messageType).xds { + if m.Has(xd) && !f(xd, m.Get(xd)) { + return + } + } +} +func (m reflectMessage) Has(fd protoreflect.FieldDescriptor) bool { + _, ok := m[m.stringKey(fd)] + return ok +} +func (m reflectMessage) Clear(protoreflect.FieldDescriptor) { + panic("invalid mutation of read-only message") +} +func (m reflectMessage) Get(fd protoreflect.FieldDescriptor) protoreflect.Value { + v, ok := m[m.stringKey(fd)] + if !ok { + switch { + case fd.IsList(): + return protoreflect.ValueOfList(reflectList{}) + case fd.IsMap(): + return protoreflect.ValueOfMap(reflectMap{}) + case fd.Message() != nil: + return protoreflect.ValueOfMessage(reflectMessage{ + messageTypeKey: messageType{md: m.Descriptor()}, + }) + default: + return fd.Default() + } + } + + // The transformation may leave Any messages in structured form. + // If so, convert them back to a raw-encoded form. + if fd.FullName() == genid.Any_Value_field_fullname { + if m, ok := v.(Message); ok { + b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) + if err != nil { + panic("BUG: " + err.Error()) + } + return protoreflect.ValueOfBytes(b) + } + } + + return reflectValueOf(v) +} +func (m reflectMessage) Set(protoreflect.FieldDescriptor, protoreflect.Value) { + panic("invalid mutation of read-only message") +} +func (m reflectMessage) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + panic("invalid mutation of read-only message") +} +func (m reflectMessage) NewField(protoreflect.FieldDescriptor) protoreflect.Value { + panic("not implemented") +} +func (m reflectMessage) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + if m.Descriptor().Oneofs().ByName(od.Name()) != od { + panic("oneof descriptor does not belong to this message") + } + fds := od.Fields() + for i := 0; i < fds.Len(); i++ { + fd := fds.Get(i) + if _, ok := m[m.stringKey(fd)]; ok { + return fd + } + } + return nil +} +func (m reflectMessage) GetUnknown() protoreflect.RawFields { + var nums []protoreflect.FieldNumber + for k := range m { + if len(strings.Trim(k, "0123456789")) == 0 { + n, _ := strconv.ParseUint(k, 10, 32) + nums = append(nums, protoreflect.FieldNumber(n)) + } + } + sort.Slice(nums, func(i, j int) bool { return nums[i] < nums[j] }) + + var raw protoreflect.RawFields + for _, num := range nums { + b, _ := m[strconv.FormatUint(uint64(num), 10)].(protoreflect.RawFields) + raw = append(raw, b...) + } + return raw +} +func (m reflectMessage) SetUnknown(protoreflect.RawFields) { + panic("invalid mutation of read-only message") +} +func (m reflectMessage) IsValid() bool { + invalid, _ := m[messageInvalidKey].(bool) + return !invalid +} +func (m reflectMessage) ProtoMethods() *protoiface.Methods { + return nil +} + +type reflectMessageType struct{ protoreflect.MessageDescriptor } + +func (t reflectMessageType) New() protoreflect.Message { + panic("not implemented") +} +func (t reflectMessageType) Zero() protoreflect.Message { + panic("not implemented") +} +func (t reflectMessageType) Descriptor() protoreflect.MessageDescriptor { + return t.MessageDescriptor +} + +type reflectList struct{ v reflect.Value } + +func (ls reflectList) Len() int { + if !ls.IsValid() { + return 0 + } + return ls.v.Len() +} +func (ls reflectList) Get(i int) protoreflect.Value { + return reflectValueOf(ls.v.Index(i).Interface()) +} +func (ls reflectList) Set(int, protoreflect.Value) { + panic("invalid mutation of read-only list") +} +func (ls reflectList) Append(protoreflect.Value) { + panic("invalid mutation of read-only list") +} +func (ls reflectList) AppendMutable() protoreflect.Value { + panic("invalid mutation of read-only list") +} +func (ls reflectList) Truncate(int) { + panic("invalid mutation of read-only list") +} +func (ls reflectList) NewElement() protoreflect.Value { + panic("not implemented") +} +func (ls reflectList) IsValid() bool { + return ls.v.IsValid() +} + +type reflectMap struct{ v reflect.Value } + +func (ms reflectMap) Len() int { + if !ms.IsValid() { + return 0 + } + return ms.v.Len() +} +func (ms reflectMap) Range(f func(protoreflect.MapKey, protoreflect.Value) bool) { + if !ms.IsValid() { + return + } + ks := ms.v.MapKeys() + for _, k := range ks { + pk := reflectValueOf(k.Interface()).MapKey() + pv := reflectValueOf(ms.v.MapIndex(k).Interface()) + if !f(pk, pv) { + return + } + } +} +func (ms reflectMap) Has(k protoreflect.MapKey) bool { + if !ms.IsValid() { + return false + } + return ms.v.MapIndex(reflect.ValueOf(k.Interface())).IsValid() +} +func (ms reflectMap) Clear(protoreflect.MapKey) { + panic("invalid mutation of read-only list") +} +func (ms reflectMap) Get(k protoreflect.MapKey) protoreflect.Value { + if !ms.IsValid() { + return protoreflect.Value{} + } + v := ms.v.MapIndex(reflect.ValueOf(k.Interface())) + if !v.IsValid() { + return protoreflect.Value{} + } + return reflectValueOf(v.Interface()) +} +func (ms reflectMap) Set(protoreflect.MapKey, protoreflect.Value) { + panic("invalid mutation of read-only list") +} +func (ms reflectMap) Mutable(k protoreflect.MapKey) protoreflect.Value { + panic("invalid mutation of read-only list") +} +func (ms reflectMap) NewValue() protoreflect.Value { + panic("not implemented") +} +func (ms reflectMap) IsValid() bool { + return ms.v.IsValid() +} diff --git a/vendor/google.golang.org/protobuf/testing/protocmp/util.go b/vendor/google.golang.org/protobuf/testing/protocmp/util.go new file mode 100644 index 00000000..668bb2e9 --- /dev/null +++ b/vendor/google.golang.org/protobuf/testing/protocmp/util.go @@ -0,0 +1,679 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protocmp + +import ( + "bytes" + "fmt" + "math" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" +) + +var ( + enumReflectType = reflect.TypeOf(Enum{}) + messageReflectType = reflect.TypeOf(Message{}) +) + +// FilterEnum filters opt to only be applicable on standalone Enums, +// singular fields of enums, list fields of enums, or map fields of enum values, +// where the enum is the same type as the specified enum. +// +// The Go type of the last path step may be an: +// • Enum for singular fields, elements of a repeated field, +// values of a map field, or standalone Enums +// • []Enum for list fields +// • map[K]Enum for map fields +// • interface{} for a Message map entry value +// +// This must be used in conjunction with Transform. +func FilterEnum(enum protoreflect.Enum, opt cmp.Option) cmp.Option { + return FilterDescriptor(enum.Descriptor(), opt) +} + +// FilterMessage filters opt to only be applicable on standalone Messages, +// singular fields of messages, list fields of messages, or map fields of +// message values, where the message is the same type as the specified message. +// +// The Go type of the last path step may be an: +// • Message for singular fields, elements of a repeated field, +// values of a map field, or standalone Messages +// • []Message for list fields +// • map[K]Message for map fields +// • interface{} for a Message map entry value +// +// This must be used in conjunction with Transform. +func FilterMessage(message proto.Message, opt cmp.Option) cmp.Option { + return FilterDescriptor(message.ProtoReflect().Descriptor(), opt) +} + +// FilterField filters opt to only be applicable on the specified field +// in the message. It panics if a field of the given name does not exist. +// +// The Go type of the last path step may be an: +// • T for singular fields +// • []T for list fields +// • map[K]T for map fields +// • interface{} for a Message map entry value +// +// This must be used in conjunction with Transform. +func FilterField(message proto.Message, name protoreflect.Name, opt cmp.Option) cmp.Option { + md := message.ProtoReflect().Descriptor() + return FilterDescriptor(mustFindFieldDescriptor(md, name), opt) +} + +// FilterOneof filters opt to only be applicable on all fields within the +// specified oneof in the message. It panics if a oneof of the given name +// does not exist. +// +// The Go type of the last path step may be an: +// • T for singular fields +// • []T for list fields +// • map[K]T for map fields +// • interface{} for a Message map entry value +// +// This must be used in conjunction with Transform. +func FilterOneof(message proto.Message, name protoreflect.Name, opt cmp.Option) cmp.Option { + md := message.ProtoReflect().Descriptor() + return FilterDescriptor(mustFindOneofDescriptor(md, name), opt) +} + +// FilterDescriptor ignores the specified descriptor. +// +// The following descriptor types may be specified: +// • protoreflect.EnumDescriptor +// • protoreflect.MessageDescriptor +// • protoreflect.FieldDescriptor +// • protoreflect.OneofDescriptor +// +// For the behavior of each, see the corresponding filter function. +// Since this filter accepts a protoreflect.FieldDescriptor, it can be used +// to also filter for extension fields as a protoreflect.ExtensionDescriptor +// is just an alias to protoreflect.FieldDescriptor. +// +// This must be used in conjunction with Transform. +func FilterDescriptor(desc protoreflect.Descriptor, opt cmp.Option) cmp.Option { + f := newNameFilters(desc) + return cmp.FilterPath(f.Filter, opt) +} + +// IgnoreEnums ignores all enums of the specified types. +// It is equivalent to FilterEnum(enum, cmp.Ignore()) for each enum. +// +// This must be used in conjunction with Transform. +func IgnoreEnums(enums ...protoreflect.Enum) cmp.Option { + var ds []protoreflect.Descriptor + for _, e := range enums { + ds = append(ds, e.Descriptor()) + } + return IgnoreDescriptors(ds...) +} + +// IgnoreMessages ignores all messages of the specified types. +// It is equivalent to FilterMessage(message, cmp.Ignore()) for each message. +// +// This must be used in conjunction with Transform. +func IgnoreMessages(messages ...proto.Message) cmp.Option { + var ds []protoreflect.Descriptor + for _, m := range messages { + ds = append(ds, m.ProtoReflect().Descriptor()) + } + return IgnoreDescriptors(ds...) +} + +// IgnoreFields ignores the specified fields in the specified message. +// It is equivalent to FilterField(message, name, cmp.Ignore()) for each field +// in the message. +// +// This must be used in conjunction with Transform. +func IgnoreFields(message proto.Message, names ...protoreflect.Name) cmp.Option { + var ds []protoreflect.Descriptor + md := message.ProtoReflect().Descriptor() + for _, s := range names { + ds = append(ds, mustFindFieldDescriptor(md, s)) + } + return IgnoreDescriptors(ds...) +} + +// IgnoreOneofs ignores fields of the specified oneofs in the specified message. +// It is equivalent to FilterOneof(message, name, cmp.Ignore()) for each oneof +// in the message. +// +// This must be used in conjunction with Transform. +func IgnoreOneofs(message proto.Message, names ...protoreflect.Name) cmp.Option { + var ds []protoreflect.Descriptor + md := message.ProtoReflect().Descriptor() + for _, s := range names { + ds = append(ds, mustFindOneofDescriptor(md, s)) + } + return IgnoreDescriptors(ds...) +} + +// IgnoreDescriptors ignores the specified set of descriptors. +// It is equivalent to FilterDescriptor(desc, cmp.Ignore()) for each descriptor. +// +// This must be used in conjunction with Transform. +func IgnoreDescriptors(descs ...protoreflect.Descriptor) cmp.Option { + return cmp.FilterPath(newNameFilters(descs...).Filter, cmp.Ignore()) +} + +func mustFindFieldDescriptor(md protoreflect.MessageDescriptor, s protoreflect.Name) protoreflect.FieldDescriptor { + d := findDescriptor(md, s) + if fd, ok := d.(protoreflect.FieldDescriptor); ok && fd.Name() == s { + return fd + } + + var suggestion string + switch d.(type) { + case protoreflect.FieldDescriptor: + suggestion = fmt.Sprintf("; consider specifying field %q instead", d.Name()) + case protoreflect.OneofDescriptor: + suggestion = fmt.Sprintf("; consider specifying oneof %q with IgnoreOneofs instead", d.Name()) + } + panic(fmt.Sprintf("message %q has no field %q%s", md.FullName(), s, suggestion)) +} + +func mustFindOneofDescriptor(md protoreflect.MessageDescriptor, s protoreflect.Name) protoreflect.OneofDescriptor { + d := findDescriptor(md, s) + if od, ok := d.(protoreflect.OneofDescriptor); ok && d.Name() == s { + return od + } + + var suggestion string + switch d.(type) { + case protoreflect.OneofDescriptor: + suggestion = fmt.Sprintf("; consider specifying oneof %q instead", d.Name()) + case protoreflect.FieldDescriptor: + suggestion = fmt.Sprintf("; consider specifying field %q with IgnoreFields instead", d.Name()) + } + panic(fmt.Sprintf("message %q has no oneof %q%s", md.FullName(), s, suggestion)) +} + +func findDescriptor(md protoreflect.MessageDescriptor, s protoreflect.Name) protoreflect.Descriptor { + // Exact match. + if fd := md.Fields().ByName(s); fd != nil { + return fd + } + if od := md.Oneofs().ByName(s); od != nil { + return od + } + + // Best-effort match. + // + // It's a common user mistake to use the CameCased field name as it appears + // in the generated Go struct. Instead of complaining that it doesn't exist, + // suggest the real protobuf name that the user may have desired. + normalize := func(s protoreflect.Name) string { + return strings.Replace(strings.ToLower(string(s)), "_", "", -1) + } + for i := 0; i < md.Fields().Len(); i++ { + if fd := md.Fields().Get(i); normalize(fd.Name()) == normalize(s) { + return fd + } + } + for i := 0; i < md.Oneofs().Len(); i++ { + if od := md.Oneofs().Get(i); normalize(od.Name()) == normalize(s) { + return od + } + } + return nil +} + +type nameFilters struct { + names map[protoreflect.FullName]bool +} + +func newNameFilters(descs ...protoreflect.Descriptor) *nameFilters { + f := &nameFilters{names: make(map[protoreflect.FullName]bool)} + for _, d := range descs { + switch d := d.(type) { + case protoreflect.EnumDescriptor: + f.names[d.FullName()] = true + case protoreflect.MessageDescriptor: + f.names[d.FullName()] = true + case protoreflect.FieldDescriptor: + f.names[d.FullName()] = true + case protoreflect.OneofDescriptor: + for i := 0; i < d.Fields().Len(); i++ { + f.names[d.Fields().Get(i).FullName()] = true + } + default: + panic("invalid descriptor type") + } + } + return f +} + +func (f *nameFilters) Filter(p cmp.Path) bool { + vx, vy := p.Last().Values() + return (f.filterValue(vx) && f.filterValue(vy)) || f.filterFields(p) +} + +func (f *nameFilters) filterFields(p cmp.Path) bool { + // Trim off trailing type-assertions so that the filter can match on the + // concrete value held within an interface value. + if _, ok := p.Last().(cmp.TypeAssertion); ok { + p = p[:len(p)-1] + } + + // Filter for Message maps. + mi, ok := p.Index(-1).(cmp.MapIndex) + if !ok { + return false + } + ps := p.Index(-2) + if ps.Type() != messageReflectType { + return false + } + + // Check field name. + vx, vy := ps.Values() + mx := vx.Interface().(Message) + my := vy.Interface().(Message) + k := mi.Key().String() + if f.filterFieldName(mx, k) && f.filterFieldName(my, k) { + return true + } + + // Check field value. + vx, vy = mi.Values() + if f.filterFieldValue(vx) && f.filterFieldValue(vy) { + return true + } + + return false +} + +func (f *nameFilters) filterFieldName(m Message, k string) bool { + if md := m.Descriptor(); md != nil { + switch { + case protoreflect.Name(k).IsValid(): + return f.names[md.Fields().ByName(protoreflect.Name(k)).FullName()] + case strings.HasPrefix(k, "[") && strings.HasSuffix(k, "]"): + return f.names[protoreflect.FullName(k[1:len(k)-1])] + } + } + return false +} + +func (f *nameFilters) filterFieldValue(v reflect.Value) bool { + if !v.IsValid() { + return true // implies missing slice element or map entry + } + v = v.Elem() // map entries are always populated values + switch t := v.Type(); { + case t == enumReflectType || t == messageReflectType: + // Check for singular message or enum field. + return f.filterValue(v) + case t.Kind() == reflect.Slice && (t.Elem() == enumReflectType || t.Elem() == messageReflectType): + // Check for list field of enum or message type. + return f.filterValue(v.Index(0)) + case t.Kind() == reflect.Map && (t.Elem() == enumReflectType || t.Elem() == messageReflectType): + // Check for map field of enum or message type. + return f.filterValue(v.MapIndex(v.MapKeys()[0])) + } + return false +} + +func (f *nameFilters) filterValue(v reflect.Value) bool { + if !v.IsValid() { + return true // implies missing slice element or map entry + } + if !v.CanInterface() { + return false // implies unexported struct field + } + switch v := v.Interface().(type) { + case Enum: + return v.Descriptor() != nil && f.names[v.Descriptor().FullName()] + case Message: + return v.Descriptor() != nil && f.names[v.Descriptor().FullName()] + } + return false +} + +// IgnoreDefaultScalars ignores singular scalars that are unpopulated or +// explicitly set to the default value. +// This option does not effect elements in a list or entries in a map. +// +// This must be used in conjunction with Transform. +func IgnoreDefaultScalars() cmp.Option { + return cmp.FilterPath(func(p cmp.Path) bool { + // Filter for Message maps. + mi, ok := p.Index(-1).(cmp.MapIndex) + if !ok { + return false + } + ps := p.Index(-2) + if ps.Type() != messageReflectType { + return false + } + + // Check whether both fields are default or unpopulated scalars. + vx, vy := ps.Values() + mx := vx.Interface().(Message) + my := vy.Interface().(Message) + k := mi.Key().String() + return isDefaultScalar(mx, k) && isDefaultScalar(my, k) + }, cmp.Ignore()) +} + +func isDefaultScalar(m Message, k string) bool { + if _, ok := m[k]; !ok { + return true + } + + var fd protoreflect.FieldDescriptor + switch mt := m[messageTypeKey].(messageType); { + case protoreflect.Name(k).IsValid(): + fd = mt.md.Fields().ByName(protoreflect.Name(k)) + case strings.HasPrefix(k, "[") && strings.HasSuffix(k, "]"): + fd = mt.xds[protoreflect.FullName(k[1:len(k)-1])] + } + if fd == nil || !fd.Default().IsValid() { + return false + } + switch fd.Kind() { + case protoreflect.BytesKind: + v, ok := m[k].([]byte) + return ok && bytes.Equal(fd.Default().Bytes(), v) + case protoreflect.FloatKind: + v, ok := m[k].(float32) + return ok && equalFloat64(fd.Default().Float(), float64(v)) + case protoreflect.DoubleKind: + v, ok := m[k].(float64) + return ok && equalFloat64(fd.Default().Float(), float64(v)) + case protoreflect.EnumKind: + v, ok := m[k].(Enum) + return ok && fd.Default().Enum() == v.Number() + default: + return reflect.DeepEqual(fd.Default().Interface(), m[k]) + } +} + +func equalFloat64(x, y float64) bool { + return x == y || (math.IsNaN(x) && math.IsNaN(y)) +} + +// IgnoreEmptyMessages ignores messages that are empty or unpopulated. +// It applies to standalone Messages, singular message fields, +// list fields of messages, and map fields of message values. +// +// This must be used in conjunction with Transform. +func IgnoreEmptyMessages() cmp.Option { + return cmp.FilterPath(func(p cmp.Path) bool { + vx, vy := p.Last().Values() + return (isEmptyMessage(vx) && isEmptyMessage(vy)) || isEmptyMessageFields(p) + }, cmp.Ignore()) +} + +func isEmptyMessageFields(p cmp.Path) bool { + // Filter for Message maps. + mi, ok := p.Index(-1).(cmp.MapIndex) + if !ok { + return false + } + ps := p.Index(-2) + if ps.Type() != messageReflectType { + return false + } + + // Check field value. + vx, vy := mi.Values() + if isEmptyMessageFieldValue(vx) && isEmptyMessageFieldValue(vy) { + return true + } + + return false +} + +func isEmptyMessageFieldValue(v reflect.Value) bool { + if !v.IsValid() { + return true // implies missing slice element or map entry + } + v = v.Elem() // map entries are always populated values + switch t := v.Type(); { + case t == messageReflectType: + // Check singular field for empty message. + if !isEmptyMessage(v) { + return false + } + case t.Kind() == reflect.Slice && t.Elem() == messageReflectType: + // Check list field for all empty message elements. + for i := 0; i < v.Len(); i++ { + if !isEmptyMessage(v.Index(i)) { + return false + } + } + case t.Kind() == reflect.Map && t.Elem() == messageReflectType: + // Check map field for all empty message values. + for _, k := range v.MapKeys() { + if !isEmptyMessage(v.MapIndex(k)) { + return false + } + } + default: + return false + } + return true +} + +func isEmptyMessage(v reflect.Value) bool { + if !v.IsValid() { + return true // implies missing slice element or map entry + } + if !v.CanInterface() { + return false // implies unexported struct field + } + if m, ok := v.Interface().(Message); ok { + for k := range m { + if k != messageTypeKey && k != messageInvalidKey { + return false + } + } + return true + } + return false +} + +// IgnoreUnknown ignores unknown fields in all messages. +// +// This must be used in conjunction with Transform. +func IgnoreUnknown() cmp.Option { + return cmp.FilterPath(func(p cmp.Path) bool { + // Filter for Message maps. + mi, ok := p.Index(-1).(cmp.MapIndex) + if !ok { + return false + } + ps := p.Index(-2) + if ps.Type() != messageReflectType { + return false + } + + // Filter for unknown fields (which always have a numeric map key). + return strings.Trim(mi.Key().String(), "0123456789") == "" + }, cmp.Ignore()) +} + +// SortRepeated sorts repeated fields of the specified element type. +// The less function must be of the form "func(T, T) bool" where T is the +// Go element type for the repeated field kind. +// +// The element type T can be one of the following: +// • Go type for a protobuf scalar kind except for an enum +// (i.e., bool, int32, int64, uint32, uint64, float32, float64, string, and []byte) +// • E where E is a concrete enum type that implements protoreflect.Enum +// • M where M is a concrete message type that implement proto.Message +// +// This option only applies to repeated fields within a protobuf message. +// It does not operate on higher-order Go types that seem like a repeated field. +// For example, a []T outside the context of a protobuf message will not be +// handled by this option. To sort Go slices that are not repeated fields, +// consider using "github.com/google/go-cmp/cmp/cmpopts".SortSlices instead. +// +// This must be used in conjunction with Transform. +func SortRepeated(lessFunc interface{}) cmp.Option { + t, ok := checkTTBFunc(lessFunc) + if !ok { + panic(fmt.Sprintf("invalid less function: %T", lessFunc)) + } + + var opt cmp.Option + var sliceType reflect.Type + switch vf := reflect.ValueOf(lessFunc); { + case t.Implements(enumV2Type): + et := reflect.Zero(t).Interface().(protoreflect.Enum).Type() + lessFunc = func(x, y Enum) bool { + vx := reflect.ValueOf(et.New(x.Number())) + vy := reflect.ValueOf(et.New(y.Number())) + return vf.Call([]reflect.Value{vx, vy})[0].Bool() + } + opt = FilterDescriptor(et.Descriptor(), cmpopts.SortSlices(lessFunc)) + sliceType = reflect.SliceOf(enumReflectType) + case t.Implements(messageV2Type): + mt := reflect.Zero(t).Interface().(protoreflect.ProtoMessage).ProtoReflect().Type() + lessFunc = func(x, y Message) bool { + mx := mt.New().Interface() + my := mt.New().Interface() + proto.Merge(mx, x) + proto.Merge(my, y) + vx := reflect.ValueOf(mx) + vy := reflect.ValueOf(my) + return vf.Call([]reflect.Value{vx, vy})[0].Bool() + } + opt = FilterDescriptor(mt.Descriptor(), cmpopts.SortSlices(lessFunc)) + sliceType = reflect.SliceOf(messageReflectType) + default: + switch t { + case reflect.TypeOf(bool(false)): + case reflect.TypeOf(int32(0)): + case reflect.TypeOf(int64(0)): + case reflect.TypeOf(uint32(0)): + case reflect.TypeOf(uint64(0)): + case reflect.TypeOf(float32(0)): + case reflect.TypeOf(float64(0)): + case reflect.TypeOf(string("")): + case reflect.TypeOf([]byte(nil)): + default: + panic(fmt.Sprintf("invalid element type: %v", t)) + } + opt = cmpopts.SortSlices(lessFunc) + sliceType = reflect.SliceOf(t) + } + + return cmp.FilterPath(func(p cmp.Path) bool { + // Filter to only apply to repeated fields within a message. + if t := p.Index(-1).Type(); t == nil || t != sliceType { + return false + } + if t := p.Index(-2).Type(); t == nil || t.Kind() != reflect.Interface { + return false + } + if t := p.Index(-3).Type(); t == nil || t != messageReflectType { + return false + } + return true + }, opt) +} + +func checkTTBFunc(lessFunc interface{}) (reflect.Type, bool) { + switch t := reflect.TypeOf(lessFunc); { + case t == nil: + return nil, false + case t.NumIn() != 2 || t.In(0) != t.In(1) || t.IsVariadic(): + return nil, false + case t.NumOut() != 1 || t.Out(0) != reflect.TypeOf(false): + return nil, false + default: + return t.In(0), true + } +} + +// SortRepeatedFields sorts the specified repeated fields. +// Sorting a repeated field is useful for treating the list as a multiset +// (i.e., a set where each value can appear multiple times). +// It panics if the field does not exist or is not a repeated field. +// +// The sort ordering is as follows: +// • Booleans are sorted where false is sorted before true. +// • Integers are sorted in ascending order. +// • Floating-point numbers are sorted in ascending order according to +// the total ordering defined by IEEE-754 (section 5.10). +// • Strings and bytes are sorted lexicographically in ascending order. +// • Enums are sorted in ascending order based on its numeric value. +// • Messages are sorted according to some arbitrary ordering +// which is undefined and may change in future implementations. +// +// The ordering chosen for repeated messages is unlikely to be aesthetically +// preferred by humans. Consider using a custom sort function: +// +// FilterField(m, "foo_field", SortRepeated(func(x, y *foopb.MyMessage) bool { +// ... // user-provided definition for less +// })) +// +// This must be used in conjunction with Transform. +func SortRepeatedFields(message proto.Message, names ...protoreflect.Name) cmp.Option { + var opts cmp.Options + md := message.ProtoReflect().Descriptor() + for _, name := range names { + fd := mustFindFieldDescriptor(md, name) + if !fd.IsList() { + panic(fmt.Sprintf("message field %q is not repeated", fd.FullName())) + } + + var lessFunc interface{} + switch fd.Kind() { + case protoreflect.BoolKind: + lessFunc = func(x, y bool) bool { return !x && y } + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + lessFunc = func(x, y int32) bool { return x < y } + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + lessFunc = func(x, y int64) bool { return x < y } + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + lessFunc = func(x, y uint32) bool { return x < y } + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + lessFunc = func(x, y uint64) bool { return x < y } + case protoreflect.FloatKind: + lessFunc = lessF32 + case protoreflect.DoubleKind: + lessFunc = lessF64 + case protoreflect.StringKind: + lessFunc = func(x, y string) bool { return x < y } + case protoreflect.BytesKind: + lessFunc = func(x, y []byte) bool { return bytes.Compare(x, y) < 0 } + case protoreflect.EnumKind: + lessFunc = func(x, y Enum) bool { return x.Number() < y.Number() } + case protoreflect.MessageKind, protoreflect.GroupKind: + lessFunc = func(x, y Message) bool { return x.String() < y.String() } + default: + panic(fmt.Sprintf("invalid kind: %v", fd.Kind())) + } + opts = append(opts, FilterDescriptor(fd, cmpopts.SortSlices(lessFunc))) + } + return opts +} + +func lessF32(x, y float32) bool { + // Bit-wise implementation of IEEE-754, section 5.10. + xi := int32(math.Float32bits(x)) + yi := int32(math.Float32bits(y)) + xi ^= int32(uint32(xi>>31) >> 1) + yi ^= int32(uint32(yi>>31) >> 1) + return xi < yi +} +func lessF64(x, y float64) bool { + // Bit-wise implementation of IEEE-754, section 5.10. + xi := int64(math.Float64bits(x)) + yi := int64(math.Float64bits(y)) + xi ^= int64(uint64(xi>>63) >> 1) + yi ^= int64(uint64(yi>>63) >> 1) + return xi < yi +} diff --git a/vendor/google.golang.org/protobuf/testing/protocmp/xform.go b/vendor/google.golang.org/protobuf/testing/protocmp/xform.go new file mode 100644 index 00000000..25d1302d --- /dev/null +++ b/vendor/google.golang.org/protobuf/testing/protocmp/xform.go @@ -0,0 +1,332 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package protocmp provides protobuf specific options for the +// "github.com/google/go-cmp/cmp" package. +// +// The primary feature is the Transform option, which transform proto.Message +// types into a Message map that is suitable for cmp to introspect upon. +// All other options in this package must be used in conjunction with Transform. +package protocmp + +import ( + "reflect" + "strconv" + + "github.com/google/go-cmp/cmp" + + "google.golang.org/protobuf/encoding/protowire" + "google.golang.org/protobuf/internal/genid" + "google.golang.org/protobuf/internal/msgfmt" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/runtime/protoiface" + "google.golang.org/protobuf/runtime/protoimpl" +) + +var ( + enumV2Type = reflect.TypeOf((*protoreflect.Enum)(nil)).Elem() + messageV1Type = reflect.TypeOf((*protoiface.MessageV1)(nil)).Elem() + messageV2Type = reflect.TypeOf((*proto.Message)(nil)).Elem() +) + +// Enum is a dynamic representation of a protocol buffer enum that is +// suitable for cmp.Equal and cmp.Diff to compare upon. +type Enum struct { + num protoreflect.EnumNumber + ed protoreflect.EnumDescriptor +} + +// Descriptor returns the enum descriptor. +// It returns nil for a zero Enum value. +func (e Enum) Descriptor() protoreflect.EnumDescriptor { + return e.ed +} + +// Number returns the enum value as an integer. +func (e Enum) Number() protoreflect.EnumNumber { + return e.num +} + +// Equal reports whether e1 and e2 represent the same enum value. +func (e1 Enum) Equal(e2 Enum) bool { + if e1.ed.FullName() != e2.ed.FullName() { + return false + } + return e1.num == e2.num +} + +// String returns the name of the enum value if known (e.g., "ENUM_VALUE"), +// otherwise it returns the formatted decimal enum number (e.g., "14"). +func (e Enum) String() string { + if ev := e.ed.Values().ByNumber(e.num); ev != nil { + return string(ev.Name()) + } + return strconv.Itoa(int(e.num)) +} + +const ( + messageTypeKey = "@type" + messageInvalidKey = "@invalid" +) + +type messageType struct { + md protoreflect.MessageDescriptor + xds map[protoreflect.FullName]protoreflect.ExtensionDescriptor +} + +func (t messageType) String() string { + return string(t.md.FullName()) +} + +func (t1 messageType) Equal(t2 messageType) bool { + return t1.md.FullName() == t2.md.FullName() +} + +// Message is a dynamic representation of a protocol buffer message that is +// suitable for cmp.Equal and cmp.Diff to directly operate upon. +// +// Every populated known field (excluding extension fields) is stored in the map +// with the key being the short name of the field (e.g., "field_name") and +// the value determined by the kind and cardinality of the field. +// +// Singular scalars are represented by the same Go type as protoreflect.Value, +// singular messages are represented by the Message type, +// singular enums are represented by the Enum type, +// list fields are represented as a Go slice, and +// map fields are represented as a Go map. +// +// Every populated extension field is stored in the map with the key being the +// full name of the field surrounded by brackets (e.g., "[extension.full.name]") +// and the value determined according to the same rules as known fields. +// +// Every unknown field is stored in the map with the key being the field number +// encoded as a decimal string (e.g., "132") and the value being the raw bytes +// of the encoded field (as the protoreflect.RawFields type). +// +// Message values must not be created by or mutated by users. +type Message map[string]interface{} + +// Descriptor return the message descriptor. +// It returns nil for a zero Message value. +func (m Message) Descriptor() protoreflect.MessageDescriptor { + mt, _ := m[messageTypeKey].(messageType) + return mt.md +} + +// ProtoReflect returns a reflective view of m. +// It only implements the read-only operations of protoreflect.Message. +// Calling any mutating operations on m panics. +func (m Message) ProtoReflect() protoreflect.Message { + return (reflectMessage)(m) +} + +// ProtoMessage is a marker method from the legacy message interface. +func (m Message) ProtoMessage() {} + +// Reset is the required Reset method from the legacy message interface. +func (m Message) Reset() { + panic("invalid mutation of a read-only message") +} + +// String returns a formatted string for the message. +// It is intended for human debugging and has no guarantees about its +// exact format or the stability of its output. +func (m Message) String() string { + switch { + case m == nil: + return "" + case !m.ProtoReflect().IsValid(): + return "" + default: + return msgfmt.Format(m) + } +} + +type option struct{} + +// Transform returns a cmp.Option that converts each proto.Message to a Message. +// The transformation does not mutate nor alias any converted messages. +// +// The google.protobuf.Any message is automatically unmarshaled such that the +// "value" field is a Message representing the underlying message value +// assuming it could be resolved and properly unmarshaled. +// +// This does not directly transform higher-order composite Go types. +// For example, []*foopb.Message is not transformed into []Message, +// but rather the individual message elements of the slice are transformed. +// +// Note that there are currently no custom options for Transform, +// but the use of an unexported type keeps the future open. +func Transform(...option) cmp.Option { + // addrType returns a pointer to t if t isn't a pointer or interface. + addrType := func(t reflect.Type) reflect.Type { + if k := t.Kind(); k == reflect.Interface || k == reflect.Ptr { + return t + } + return reflect.PtrTo(t) + } + + // TODO: Should this transform protoreflect.Enum types to Enum as well? + return cmp.FilterPath(func(p cmp.Path) bool { + ps := p.Last() + if isMessageType(addrType(ps.Type())) { + return true + } + + // Check whether the concrete values of an interface both satisfy + // the Message interface. + if ps.Type().Kind() == reflect.Interface { + vx, vy := ps.Values() + if !vx.IsValid() || vx.IsNil() || !vy.IsValid() || vy.IsNil() { + return false + } + return isMessageType(addrType(vx.Elem().Type())) && isMessageType(addrType(vy.Elem().Type())) + } + + return false + }, cmp.Transformer("protocmp.Transform", func(v interface{}) Message { + // For user convenience, shallow copy the message value if necessary + // in order for it to implement the message interface. + if rv := reflect.ValueOf(v); rv.IsValid() && rv.Kind() != reflect.Ptr && !isMessageType(rv.Type()) { + pv := reflect.New(rv.Type()) + pv.Elem().Set(rv) + v = pv.Interface() + } + + m := protoimpl.X.MessageOf(v) + switch { + case m == nil: + return nil + case !m.IsValid(): + return Message{messageTypeKey: messageType{md: m.Descriptor()}, messageInvalidKey: true} + default: + return transformMessage(m) + } + })) +} + +func isMessageType(t reflect.Type) bool { + // Avoid tranforming the Message itself. + if t == reflect.TypeOf(Message(nil)) || t == reflect.TypeOf((*Message)(nil)) { + return false + } + return t.Implements(messageV1Type) || t.Implements(messageV2Type) +} + +func transformMessage(m protoreflect.Message) Message { + mx := Message{} + mt := messageType{md: m.Descriptor(), xds: make(map[protoreflect.FullName]protoreflect.FieldDescriptor)} + + // Handle known and extension fields. + m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { + s := string(fd.Name()) + if fd.IsExtension() { + s = "[" + string(fd.FullName()) + "]" + mt.xds[fd.FullName()] = fd + } + switch { + case fd.IsList(): + mx[s] = transformList(fd, v.List()) + case fd.IsMap(): + mx[s] = transformMap(fd, v.Map()) + default: + mx[s] = transformSingular(fd, v) + } + return true + }) + + // Handle unknown fields. + for b := m.GetUnknown(); len(b) > 0; { + num, _, n := protowire.ConsumeField(b) + s := strconv.Itoa(int(num)) + b2, _ := mx[s].(protoreflect.RawFields) + mx[s] = append(b2, b[:n]...) + b = b[n:] + } + + // Expand Any messages. + if mt.md.FullName() == genid.Any_message_fullname { + // TODO: Expose Transform option to specify a custom resolver? + s, _ := mx[string(genid.Any_TypeUrl_field_name)].(string) + b, _ := mx[string(genid.Any_Value_field_name)].([]byte) + mt, err := protoregistry.GlobalTypes.FindMessageByURL(s) + if mt != nil && err == nil { + m2 := mt.New() + err := proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(b, m2.Interface()) + if err == nil { + mx[string(genid.Any_Value_field_name)] = transformMessage(m2) + } + } + } + + mx[messageTypeKey] = mt + return mx +} + +func transformList(fd protoreflect.FieldDescriptor, lv protoreflect.List) interface{} { + t := protoKindToGoType(fd.Kind()) + rv := reflect.MakeSlice(reflect.SliceOf(t), lv.Len(), lv.Len()) + for i := 0; i < lv.Len(); i++ { + v := reflect.ValueOf(transformSingular(fd, lv.Get(i))) + rv.Index(i).Set(v) + } + return rv.Interface() +} + +func transformMap(fd protoreflect.FieldDescriptor, mv protoreflect.Map) interface{} { + kfd := fd.MapKey() + vfd := fd.MapValue() + kt := protoKindToGoType(kfd.Kind()) + vt := protoKindToGoType(vfd.Kind()) + rv := reflect.MakeMapWithSize(reflect.MapOf(kt, vt), mv.Len()) + mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { + kv := reflect.ValueOf(transformSingular(kfd, k.Value())) + vv := reflect.ValueOf(transformSingular(vfd, v)) + rv.SetMapIndex(kv, vv) + return true + }) + return rv.Interface() +} + +func transformSingular(fd protoreflect.FieldDescriptor, v protoreflect.Value) interface{} { + switch fd.Kind() { + case protoreflect.EnumKind: + return Enum{num: v.Enum(), ed: fd.Enum()} + case protoreflect.MessageKind, protoreflect.GroupKind: + return transformMessage(v.Message()) + default: + return v.Interface() + } +} + +func protoKindToGoType(k protoreflect.Kind) reflect.Type { + switch k { + case protoreflect.BoolKind: + return reflect.TypeOf(bool(false)) + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + return reflect.TypeOf(int32(0)) + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + return reflect.TypeOf(int64(0)) + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + return reflect.TypeOf(uint32(0)) + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + return reflect.TypeOf(uint64(0)) + case protoreflect.FloatKind: + return reflect.TypeOf(float32(0)) + case protoreflect.DoubleKind: + return reflect.TypeOf(float64(0)) + case protoreflect.StringKind: + return reflect.TypeOf(string("")) + case protoreflect.BytesKind: + return reflect.TypeOf([]byte(nil)) + case protoreflect.EnumKind: + return reflect.TypeOf(Enum{}) + case protoreflect.MessageKind, protoreflect.GroupKind: + return reflect.TypeOf(Message{}) + default: + panic("invalid kind") + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 50bb863c..4fcb4578 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -9,6 +9,13 @@ github.com/golang/protobuf/ptypes github.com/golang/protobuf/ptypes/any github.com/golang/protobuf/ptypes/duration github.com/golang/protobuf/ptypes/timestamp +# github.com/google/go-cmp v0.5.0 +github.com/google/go-cmp/cmp +github.com/google/go-cmp/cmp/cmpopts +github.com/google/go-cmp/cmp/internal/diff +github.com/google/go-cmp/cmp/internal/flags +github.com/google/go-cmp/cmp/internal/function +github.com/google/go-cmp/cmp/internal/value # github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 github.com/iancoleman/strcase # github.com/kubernetes-csi/csi-proxy/client v0.0.0-00010101000000-000000000000 => ./client @@ -18,6 +25,7 @@ github.com/kubernetes-csi/csi-proxy/client/api/disk/v1beta1 github.com/kubernetes-csi/csi-proxy/client/api/disk/v1beta2 github.com/kubernetes-csi/csi-proxy/client/api/filesystem/v1alpha1 github.com/kubernetes-csi/csi-proxy/client/api/filesystem/v1beta1 +github.com/kubernetes-csi/csi-proxy/client/api/iscsi/v1alpha1 github.com/kubernetes-csi/csi-proxy/client/api/smb/v1alpha1 github.com/kubernetes-csi/csi-proxy/client/api/smb/v1beta1 github.com/kubernetes-csi/csi-proxy/client/api/system/v1alpha1 @@ -28,6 +36,7 @@ github.com/kubernetes-csi/csi-proxy/client/apiversion github.com/kubernetes-csi/csi-proxy/client/groups/disk/v1beta1 github.com/kubernetes-csi/csi-proxy/client/groups/disk/v1beta2 github.com/kubernetes-csi/csi-proxy/client/groups/filesystem/v1beta1 +github.com/kubernetes-csi/csi-proxy/client/groups/iscsi/v1alpha1 github.com/kubernetes-csi/csi-proxy/client/groups/smb/v1beta1 github.com/kubernetes-csi/csi-proxy/client/groups/system/v1alpha1 github.com/kubernetes-csi/csi-proxy/client/groups/volume/v1alpha1 @@ -71,6 +80,9 @@ golang.org/x/tools/internal/gopathwalk golang.org/x/tools/internal/imports golang.org/x/tools/internal/module golang.org/x/tools/internal/semver +# golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +golang.org/x/xerrors +golang.org/x/xerrors/internal # google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/genproto/googleapis/rpc/status # google.golang.org/grpc v1.27.1 @@ -128,6 +140,7 @@ google.golang.org/protobuf/internal/flags google.golang.org/protobuf/internal/genid google.golang.org/protobuf/internal/impl google.golang.org/protobuf/internal/mapsort +google.golang.org/protobuf/internal/msgfmt google.golang.org/protobuf/internal/pragma google.golang.org/protobuf/internal/set google.golang.org/protobuf/internal/strs @@ -137,6 +150,7 @@ google.golang.org/protobuf/reflect/protoreflect google.golang.org/protobuf/reflect/protoregistry google.golang.org/protobuf/runtime/protoiface google.golang.org/protobuf/runtime/protoimpl +google.golang.org/protobuf/testing/protocmp google.golang.org/protobuf/types/known/anypb google.golang.org/protobuf/types/known/durationpb google.golang.org/protobuf/types/known/timestamppb