diff --git a/backend/api/experiment.proto b/backend/api/experiment.proto index c59948941f1..0ca43bbbc89 100644 --- a/backend/api/experiment.proto +++ b/backend/api/experiment.proto @@ -87,6 +87,20 @@ service ExperimentService { delete: "/apis/v1beta1/experiments/{id}" }; } + + //Archive an experiment. + rpc ArchiveExperiment(ArchiveExperimentRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/apis/v1beta1/experiments/{id}:archive" + }; + } + + //Restore an archived experiment. + rpc UnarchiveExperiment(UnarchiveExperimentRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/apis/v1beta1/experiments/{id}:unarchive" + }; + } } message CreateExperimentRequest { @@ -150,4 +164,20 @@ message Experiment { // Optional input field. Specify which resource this run belongs to. // For Experiment, the only valid resource reference is a single Namespace. repeated ResourceReference resource_references = 5; + + enum StorageState { + STORAGESTATE_UNSPECIFIED = 0; + STORAGESTATE_AVAILABLE = 1; + STORAGESTATE_ARCHIVED = 2; + } + + StorageState storage_state = 6; +} + +message ArchiveExperimentRequest { + string id = 1; +} + +message UnarchiveExperimentRequest { + string id = 1; } diff --git a/backend/api/go_client/experiment.pb.go b/backend/api/go_client/experiment.pb.go index 6f7cee687b2..a352408cdfa 100755 --- a/backend/api/go_client/experiment.pb.go +++ b/backend/api/go_client/experiment.pb.go @@ -41,6 +41,32 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +type Experiment_StorageState int32 + +const ( + Experiment_STORAGESTATE_UNSPECIFIED Experiment_StorageState = 0 + Experiment_STORAGESTATE_AVAILABLE Experiment_StorageState = 1 + Experiment_STORAGESTATE_ARCHIVED Experiment_StorageState = 2 +) + +var Experiment_StorageState_name = map[int32]string{ + 0: "STORAGESTATE_UNSPECIFIED", + 1: "STORAGESTATE_AVAILABLE", + 2: "STORAGESTATE_ARCHIVED", +} +var Experiment_StorageState_value = map[string]int32{ + "STORAGESTATE_UNSPECIFIED": 0, + "STORAGESTATE_AVAILABLE": 1, + "STORAGESTATE_ARCHIVED": 2, +} + +func (x Experiment_StorageState) String() string { + return proto.EnumName(Experiment_StorageState_name, int32(x)) +} +func (Experiment_StorageState) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_experiment_b177a3d23629b3a5, []int{5, 0} +} + type CreateExperimentRequest struct { Experiment *Experiment `protobuf:"bytes,1,opt,name=experiment,proto3" json:"experiment,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -52,7 +78,7 @@ func (m *CreateExperimentRequest) Reset() { *m = CreateExperimentRequest func (m *CreateExperimentRequest) String() string { return proto.CompactTextString(m) } func (*CreateExperimentRequest) ProtoMessage() {} func (*CreateExperimentRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_experiment_9974daeb6547c496, []int{0} + return fileDescriptor_experiment_b177a3d23629b3a5, []int{0} } func (m *CreateExperimentRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateExperimentRequest.Unmarshal(m, b) @@ -90,7 +116,7 @@ func (m *GetExperimentRequest) Reset() { *m = GetExperimentRequest{} } func (m *GetExperimentRequest) String() string { return proto.CompactTextString(m) } func (*GetExperimentRequest) ProtoMessage() {} func (*GetExperimentRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_experiment_9974daeb6547c496, []int{1} + return fileDescriptor_experiment_b177a3d23629b3a5, []int{1} } func (m *GetExperimentRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetExperimentRequest.Unmarshal(m, b) @@ -132,7 +158,7 @@ func (m *ListExperimentsRequest) Reset() { *m = ListExperimentsRequest{} func (m *ListExperimentsRequest) String() string { return proto.CompactTextString(m) } func (*ListExperimentsRequest) ProtoMessage() {} func (*ListExperimentsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_experiment_9974daeb6547c496, []int{2} + return fileDescriptor_experiment_b177a3d23629b3a5, []int{2} } func (m *ListExperimentsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListExperimentsRequest.Unmarshal(m, b) @@ -200,7 +226,7 @@ func (m *ListExperimentsResponse) Reset() { *m = ListExperimentsResponse func (m *ListExperimentsResponse) String() string { return proto.CompactTextString(m) } func (*ListExperimentsResponse) ProtoMessage() {} func (*ListExperimentsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_experiment_9974daeb6547c496, []int{3} + return fileDescriptor_experiment_b177a3d23629b3a5, []int{3} } func (m *ListExperimentsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListExperimentsResponse.Unmarshal(m, b) @@ -252,7 +278,7 @@ func (m *DeleteExperimentRequest) Reset() { *m = DeleteExperimentRequest func (m *DeleteExperimentRequest) String() string { return proto.CompactTextString(m) } func (*DeleteExperimentRequest) ProtoMessage() {} func (*DeleteExperimentRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_experiment_9974daeb6547c496, []int{4} + return fileDescriptor_experiment_b177a3d23629b3a5, []int{4} } func (m *DeleteExperimentRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DeleteExperimentRequest.Unmarshal(m, b) @@ -280,21 +306,22 @@ func (m *DeleteExperimentRequest) GetId() string { } type Experiment struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - CreatedAt *timestamp.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - ResourceReferences []*ResourceReference `protobuf:"bytes,5,rep,name=resource_references,json=resourceReferences,proto3" json:"resource_references,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + CreatedAt *timestamp.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + ResourceReferences []*ResourceReference `protobuf:"bytes,5,rep,name=resource_references,json=resourceReferences,proto3" json:"resource_references,omitempty"` + StorageState Experiment_StorageState `protobuf:"varint,6,opt,name=storage_state,json=storageState,proto3,enum=api.Experiment_StorageState" json:"storage_state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Experiment) Reset() { *m = Experiment{} } func (m *Experiment) String() string { return proto.CompactTextString(m) } func (*Experiment) ProtoMessage() {} func (*Experiment) Descriptor() ([]byte, []int) { - return fileDescriptor_experiment_9974daeb6547c496, []int{5} + return fileDescriptor_experiment_b177a3d23629b3a5, []int{5} } func (m *Experiment) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Experiment.Unmarshal(m, b) @@ -349,6 +376,89 @@ func (m *Experiment) GetResourceReferences() []*ResourceReference { return nil } +func (m *Experiment) GetStorageState() Experiment_StorageState { + if m != nil { + return m.StorageState + } + return Experiment_STORAGESTATE_UNSPECIFIED +} + +type ArchiveExperimentRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ArchiveExperimentRequest) Reset() { *m = ArchiveExperimentRequest{} } +func (m *ArchiveExperimentRequest) String() string { return proto.CompactTextString(m) } +func (*ArchiveExperimentRequest) ProtoMessage() {} +func (*ArchiveExperimentRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_experiment_b177a3d23629b3a5, []int{6} +} +func (m *ArchiveExperimentRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ArchiveExperimentRequest.Unmarshal(m, b) +} +func (m *ArchiveExperimentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ArchiveExperimentRequest.Marshal(b, m, deterministic) +} +func (dst *ArchiveExperimentRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ArchiveExperimentRequest.Merge(dst, src) +} +func (m *ArchiveExperimentRequest) XXX_Size() int { + return xxx_messageInfo_ArchiveExperimentRequest.Size(m) +} +func (m *ArchiveExperimentRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ArchiveExperimentRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ArchiveExperimentRequest proto.InternalMessageInfo + +func (m *ArchiveExperimentRequest) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +type UnarchiveExperimentRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UnarchiveExperimentRequest) Reset() { *m = UnarchiveExperimentRequest{} } +func (m *UnarchiveExperimentRequest) String() string { return proto.CompactTextString(m) } +func (*UnarchiveExperimentRequest) ProtoMessage() {} +func (*UnarchiveExperimentRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_experiment_b177a3d23629b3a5, []int{7} +} +func (m *UnarchiveExperimentRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UnarchiveExperimentRequest.Unmarshal(m, b) +} +func (m *UnarchiveExperimentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UnarchiveExperimentRequest.Marshal(b, m, deterministic) +} +func (dst *UnarchiveExperimentRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnarchiveExperimentRequest.Merge(dst, src) +} +func (m *UnarchiveExperimentRequest) XXX_Size() int { + return xxx_messageInfo_UnarchiveExperimentRequest.Size(m) +} +func (m *UnarchiveExperimentRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UnarchiveExperimentRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_UnarchiveExperimentRequest proto.InternalMessageInfo + +func (m *UnarchiveExperimentRequest) GetId() string { + if m != nil { + return m.Id + } + return "" +} + func init() { proto.RegisterType((*CreateExperimentRequest)(nil), "api.CreateExperimentRequest") proto.RegisterType((*GetExperimentRequest)(nil), "api.GetExperimentRequest") @@ -356,6 +466,9 @@ func init() { proto.RegisterType((*ListExperimentsResponse)(nil), "api.ListExperimentsResponse") proto.RegisterType((*DeleteExperimentRequest)(nil), "api.DeleteExperimentRequest") proto.RegisterType((*Experiment)(nil), "api.Experiment") + proto.RegisterType((*ArchiveExperimentRequest)(nil), "api.ArchiveExperimentRequest") + proto.RegisterType((*UnarchiveExperimentRequest)(nil), "api.UnarchiveExperimentRequest") + proto.RegisterEnum("api.Experiment_StorageState", Experiment_StorageState_name, Experiment_StorageState_value) } // Reference imports to suppress errors if they are not otherwise used. @@ -374,6 +487,8 @@ type ExperimentServiceClient interface { GetExperiment(ctx context.Context, in *GetExperimentRequest, opts ...grpc.CallOption) (*Experiment, error) ListExperiment(ctx context.Context, in *ListExperimentsRequest, opts ...grpc.CallOption) (*ListExperimentsResponse, error) DeleteExperiment(ctx context.Context, in *DeleteExperimentRequest, opts ...grpc.CallOption) (*empty.Empty, error) + ArchiveExperiment(ctx context.Context, in *ArchiveExperimentRequest, opts ...grpc.CallOption) (*empty.Empty, error) + UnarchiveExperiment(ctx context.Context, in *UnarchiveExperimentRequest, opts ...grpc.CallOption) (*empty.Empty, error) } type experimentServiceClient struct { @@ -420,12 +535,32 @@ func (c *experimentServiceClient) DeleteExperiment(ctx context.Context, in *Dele return out, nil } +func (c *experimentServiceClient) ArchiveExperiment(ctx context.Context, in *ArchiveExperimentRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/api.ExperimentService/ArchiveExperiment", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *experimentServiceClient) UnarchiveExperiment(ctx context.Context, in *UnarchiveExperimentRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/api.ExperimentService/UnarchiveExperiment", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ExperimentServiceServer is the server API for ExperimentService service. type ExperimentServiceServer interface { CreateExperiment(context.Context, *CreateExperimentRequest) (*Experiment, error) GetExperiment(context.Context, *GetExperimentRequest) (*Experiment, error) ListExperiment(context.Context, *ListExperimentsRequest) (*ListExperimentsResponse, error) DeleteExperiment(context.Context, *DeleteExperimentRequest) (*empty.Empty, error) + ArchiveExperiment(context.Context, *ArchiveExperimentRequest) (*empty.Empty, error) + UnarchiveExperiment(context.Context, *UnarchiveExperimentRequest) (*empty.Empty, error) } func RegisterExperimentServiceServer(s *grpc.Server, srv ExperimentServiceServer) { @@ -504,6 +639,42 @@ func _ExperimentService_DeleteExperiment_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } +func _ExperimentService_ArchiveExperiment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ArchiveExperimentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ExperimentServiceServer).ArchiveExperiment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.ExperimentService/ArchiveExperiment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ExperimentServiceServer).ArchiveExperiment(ctx, req.(*ArchiveExperimentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ExperimentService_UnarchiveExperiment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnarchiveExperimentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ExperimentServiceServer).UnarchiveExperiment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.ExperimentService/UnarchiveExperiment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ExperimentServiceServer).UnarchiveExperiment(ctx, req.(*UnarchiveExperimentRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _ExperimentService_serviceDesc = grpc.ServiceDesc{ ServiceName: "api.ExperimentService", HandlerType: (*ExperimentServiceServer)(nil), @@ -524,60 +695,79 @@ var _ExperimentService_serviceDesc = grpc.ServiceDesc{ MethodName: "DeleteExperiment", Handler: _ExperimentService_DeleteExperiment_Handler, }, + { + MethodName: "ArchiveExperiment", + Handler: _ExperimentService_ArchiveExperiment_Handler, + }, + { + MethodName: "UnarchiveExperiment", + Handler: _ExperimentService_UnarchiveExperiment_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "backend/api/experiment.proto", } func init() { - proto.RegisterFile("backend/api/experiment.proto", fileDescriptor_experiment_9974daeb6547c496) -} - -var fileDescriptor_experiment_9974daeb6547c496 = []byte{ - // 719 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0xcf, 0x4e, 0xfb, 0x46, - 0x10, 0xae, 0x13, 0x08, 0x64, 0xd2, 0xf0, 0x67, 0x41, 0x49, 0x70, 0x42, 0x49, 0xad, 0x8a, 0xd2, - 0xaa, 0xc4, 0x02, 0x4e, 0xed, 0x0d, 0x5a, 0x8a, 0x54, 0x5a, 0xa9, 0x32, 0x9c, 0xb8, 0x58, 0x6b, - 0x67, 0x62, 0x56, 0x71, 0xbc, 0xee, 0xee, 0x1a, 0x08, 0x55, 0x2f, 0x95, 0xfa, 0x02, 0xe5, 0xb5, - 0xda, 0x53, 0xa5, 0x3e, 0x41, 0x1f, 0xa4, 0xf2, 0xc6, 0x21, 0x4e, 0x9c, 0xe8, 0x77, 0x4a, 0x76, - 0xe6, 0xdb, 0x19, 0x7f, 0xdf, 0x7c, 0xb3, 0xd0, 0xf1, 0xa8, 0x3f, 0xc4, 0xa8, 0x6f, 0xd3, 0x98, - 0xd9, 0xf8, 0x12, 0xa3, 0x60, 0x23, 0x8c, 0x54, 0x2f, 0x16, 0x5c, 0x71, 0x52, 0xa6, 0x31, 0x33, - 0x9b, 0x73, 0x10, 0x21, 0xb8, 0x98, 0x64, 0xcd, 0xcf, 0xf2, 0x09, 0x81, 0x92, 0x27, 0xc2, 0x47, - 0x57, 0xe0, 0x00, 0x05, 0x46, 0x3e, 0x66, 0xa8, 0x4e, 0xc0, 0x79, 0x10, 0xa2, 0x06, 0xd1, 0x28, - 0xe2, 0x8a, 0x2a, 0xc6, 0x23, 0x99, 0x65, 0xdb, 0x59, 0x56, 0x9f, 0xbc, 0x64, 0x60, 0xe3, 0x28, - 0x56, 0xe3, 0x2c, 0x79, 0xb4, 0x98, 0x54, 0x6c, 0x84, 0x52, 0xd1, 0x51, 0x9c, 0x01, 0xbe, 0xd2, - 0x3f, 0xfe, 0x69, 0x80, 0xd1, 0xa9, 0x7c, 0xa6, 0x41, 0x80, 0xc2, 0xe6, 0xb1, 0xae, 0x5f, 0xec, - 0x65, 0xfd, 0x00, 0xcd, 0x6f, 0x05, 0x52, 0x85, 0xd7, 0xef, 0x3c, 0x1d, 0xfc, 0x25, 0x41, 0xa9, - 0x88, 0x0d, 0x30, 0x23, 0xdf, 0x32, 0xba, 0xc6, 0x49, 0xed, 0x7c, 0xbb, 0x47, 0x63, 0xd6, 0xcb, - 0x61, 0x73, 0x10, 0xeb, 0x18, 0xf6, 0x6f, 0x50, 0x15, 0x0b, 0x6d, 0x41, 0x89, 0xf5, 0x75, 0x81, - 0xaa, 0x53, 0x62, 0x7d, 0xeb, 0x6f, 0x03, 0x1a, 0x3f, 0x32, 0x99, 0x43, 0xca, 0x29, 0xf4, 0x10, - 0x20, 0xa6, 0x01, 0xba, 0x8a, 0x0f, 0x31, 0xca, 0xae, 0x54, 0xd3, 0xc8, 0x7d, 0x1a, 0x20, 0x6d, - 0xd0, 0x07, 0x57, 0xb2, 0x57, 0x6c, 0x95, 0xba, 0xc6, 0xc9, 0xba, 0xb3, 0x99, 0x06, 0xee, 0xd8, - 0x2b, 0x92, 0x26, 0x6c, 0x48, 0x2e, 0x94, 0xeb, 0x8d, 0x5b, 0x65, 0x7d, 0xb1, 0x92, 0x1e, 0xaf, - 0xc6, 0xa4, 0x01, 0x95, 0x01, 0x0b, 0x15, 0x8a, 0xd6, 0xda, 0x24, 0x3e, 0x39, 0x91, 0xef, 0xa1, - 0x51, 0x9c, 0x90, 0x3b, 0xc4, 0x71, 0x6b, 0x5d, 0x93, 0xdd, 0xd1, 0x64, 0x9d, 0x0c, 0x72, 0x8b, - 0x63, 0x67, 0x7f, 0x8a, 0x77, 0xa6, 0xf0, 0x5b, 0x1c, 0x5b, 0x6f, 0x06, 0x34, 0x0b, 0x7c, 0x64, - 0xcc, 0x23, 0x89, 0xe4, 0x0c, 0x6a, 0x33, 0x85, 0x64, 0xcb, 0xe8, 0x96, 0x97, 0xa9, 0x98, 0xc7, - 0xa4, 0x1a, 0x28, 0xae, 0x68, 0x38, 0x61, 0x59, 0xd6, 0x2c, 0xab, 0x3a, 0xa2, 0x69, 0x1e, 0xc3, - 0x76, 0x84, 0x2f, 0xca, 0xcd, 0xe9, 0x54, 0xd2, 0xb4, 0xea, 0x69, 0xf8, 0xe7, 0xa9, 0x56, 0xd6, - 0x17, 0xd0, 0xfc, 0x0e, 0x43, 0x5c, 0x36, 0xd9, 0xc5, 0x81, 0xfc, 0x6b, 0x00, 0xcc, 0x50, 0x8b, - 0x69, 0x42, 0x60, 0x2d, 0xa2, 0x23, 0xcc, 0xda, 0xe8, 0xff, 0xa4, 0x0b, 0xb5, 0x3e, 0x4a, 0x5f, - 0x30, 0xed, 0xac, 0x4c, 0xf0, 0x7c, 0x88, 0x7c, 0x0d, 0xe0, 0x6b, 0x67, 0xf5, 0x5d, 0xaa, 0xb4, - 0xf2, 0xb5, 0x73, 0xb3, 0x37, 0x71, 0x6f, 0x6f, 0xea, 0xde, 0xde, 0xfd, 0xd4, 0xbd, 0x4e, 0x35, - 0x43, 0x5f, 0x2a, 0x72, 0x03, 0x7b, 0xc5, 0xc1, 0xc8, 0xd6, 0xba, 0x16, 0xaf, 0x31, 0x37, 0x95, - 0xf7, 0x41, 0x38, 0xa4, 0x30, 0x1b, 0x79, 0xfe, 0x57, 0x19, 0x76, 0x67, 0xc4, 0xee, 0x50, 0x3c, - 0x31, 0x1f, 0x49, 0x0c, 0x3b, 0x8b, 0x9e, 0x27, 0x1d, 0x5d, 0x75, 0xc5, 0x2a, 0x98, 0x8b, 0x03, - 0xb3, 0x4e, 0x7f, 0xff, 0xe7, 0xbf, 0xb7, 0xd2, 0xe7, 0xd6, 0x41, 0xba, 0xc2, 0xd2, 0x7e, 0x3a, - 0xf3, 0x50, 0xd1, 0xb3, 0xdc, 0x63, 0x21, 0xbf, 0xc9, 0x6d, 0x06, 0xf1, 0xa1, 0x3e, 0xb7, 0x19, - 0xe4, 0x40, 0x17, 0x5c, 0xb6, 0x2d, 0xc5, 0x5e, 0xc7, 0xba, 0x57, 0x97, 0x7c, 0xb2, 0xb2, 0x97, - 0xfd, 0x2b, 0xeb, 0xff, 0x46, 0x22, 0xd8, 0x9a, 0x77, 0x21, 0x69, 0xeb, 0x52, 0xcb, 0x57, 0xcd, - 0xec, 0x2c, 0x4f, 0x4e, 0x7c, 0x6b, 0x7d, 0xaa, 0x9b, 0xb6, 0xc9, 0x6a, 0x82, 0xa9, 0x8c, 0x8b, - 0x06, 0xcb, 0x64, 0x5c, 0xe1, 0x3b, 0xb3, 0x51, 0x18, 0xff, 0x75, 0xfa, 0xb2, 0x4d, 0x19, 0x7e, - 0xf9, 0x01, 0x86, 0x57, 0x7f, 0x18, 0x7f, 0x5e, 0xfe, 0xe4, 0x74, 0x60, 0xa3, 0x8f, 0x03, 0x9a, - 0x84, 0x8a, 0xec, 0x92, 0x6d, 0xa8, 0x9b, 0x35, 0xdd, 0xf4, 0x4e, 0x51, 0x95, 0xc8, 0x87, 0x23, - 0x38, 0x84, 0xca, 0x15, 0x52, 0x81, 0x82, 0xec, 0x6d, 0x96, 0xcc, 0x3a, 0x4d, 0xd4, 0x23, 0x17, - 0xec, 0x55, 0x3f, 0x7b, 0xdd, 0x92, 0xf7, 0x31, 0xc0, 0x3b, 0xe0, 0xa3, 0x87, 0x8b, 0x80, 0xa9, - 0xc7, 0xc4, 0xeb, 0xf9, 0x7c, 0x64, 0x0f, 0x13, 0x0f, 0x07, 0x21, 0x7f, 0xb6, 0x63, 0x16, 0x63, - 0xc8, 0x22, 0x94, 0x76, 0xfe, 0x35, 0x0f, 0xb8, 0xeb, 0x87, 0x0c, 0x23, 0xe5, 0x55, 0xf4, 0xf7, - 0x5f, 0xfc, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x31, 0xd2, 0x37, 0xac, 0x29, 0x06, 0x00, 0x00, + proto.RegisterFile("backend/api/experiment.proto", fileDescriptor_experiment_b177a3d23629b3a5) +} + +var fileDescriptor_experiment_b177a3d23629b3a5 = []byte{ + // 889 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0x51, 0x53, 0xdb, 0x46, + 0x10, 0x8e, 0x4c, 0x70, 0xc2, 0x1a, 0x83, 0x39, 0x52, 0x5b, 0x08, 0x53, 0x5c, 0x4d, 0x87, 0xba, + 0x4c, 0xb0, 0x0a, 0x79, 0x6a, 0xde, 0x0c, 0x38, 0x94, 0x86, 0xb6, 0x19, 0xd9, 0xc9, 0x43, 0x5e, + 0x3c, 0x67, 0x79, 0x6d, 0x6e, 0xb0, 0x75, 0xea, 0xdd, 0x89, 0xc4, 0x74, 0x3a, 0xd3, 0xe9, 0x4c, + 0xff, 0x40, 0xf3, 0xb3, 0x3a, 0x7d, 0xea, 0x5f, 0xe8, 0xef, 0xe8, 0x74, 0x74, 0x96, 0x41, 0xb6, + 0xec, 0x84, 0x27, 0xb8, 0xdd, 0xcf, 0xb7, 0xf7, 0x7d, 0xfb, 0xed, 0x0a, 0xca, 0x1d, 0xea, 0x5d, + 0xa1, 0xdf, 0x75, 0x68, 0xc0, 0x1c, 0x7c, 0x1f, 0xa0, 0x60, 0x43, 0xf4, 0x55, 0x2d, 0x10, 0x5c, + 0x71, 0xb2, 0x44, 0x03, 0x66, 0x95, 0xa6, 0x20, 0x42, 0x70, 0x31, 0xce, 0x5a, 0x5f, 0x26, 0x13, + 0x02, 0x25, 0x0f, 0x85, 0x87, 0x6d, 0x81, 0x3d, 0x14, 0xe8, 0x7b, 0x18, 0xa3, 0xca, 0x7d, 0xce, + 0xfb, 0x03, 0xd4, 0x20, 0xea, 0xfb, 0x5c, 0x51, 0xc5, 0xb8, 0x2f, 0xe3, 0xec, 0x76, 0x9c, 0xd5, + 0xa7, 0x4e, 0xd8, 0x73, 0x70, 0x18, 0xa8, 0x51, 0x9c, 0xdc, 0x9d, 0x4d, 0x2a, 0x36, 0x44, 0xa9, + 0xe8, 0x30, 0x88, 0x01, 0x4f, 0xf5, 0x1f, 0xef, 0xa0, 0x8f, 0xfe, 0x81, 0x7c, 0x47, 0xfb, 0x7d, + 0x14, 0x0e, 0x0f, 0xf4, 0xfd, 0xe9, 0x5a, 0xf6, 0xf7, 0x50, 0x3a, 0x11, 0x48, 0x15, 0x36, 0x6e, + 0x79, 0xba, 0xf8, 0x73, 0x88, 0x52, 0x11, 0x07, 0xe0, 0x8e, 0xbc, 0x69, 0x54, 0x8c, 0x6a, 0xee, + 0x68, 0xbd, 0x46, 0x03, 0x56, 0x4b, 0x60, 0x13, 0x10, 0x7b, 0x0f, 0x9e, 0x9c, 0xa1, 0x4a, 0x5f, + 0xb4, 0x06, 0x19, 0xd6, 0xd5, 0x17, 0xac, 0xb8, 0x19, 0xd6, 0xb5, 0xff, 0x36, 0xa0, 0x78, 0xc1, + 0x64, 0x02, 0x29, 0x27, 0xd0, 0x1d, 0x80, 0x80, 0xf6, 0xb1, 0xad, 0xf8, 0x15, 0xfa, 0xf1, 0x4f, + 0x56, 0xa2, 0x48, 0x2b, 0x0a, 0x90, 0x6d, 0xd0, 0x87, 0xb6, 0x64, 0x37, 0x68, 0x66, 0x2a, 0x46, + 0x75, 0xd9, 0x7d, 0x1c, 0x05, 0x9a, 0xec, 0x06, 0x49, 0x09, 0x1e, 0x49, 0x2e, 0x54, 0xbb, 0x33, + 0x32, 0x97, 0xf4, 0x0f, 0xb3, 0xd1, 0xf1, 0x78, 0x44, 0x8a, 0x90, 0xed, 0xb1, 0x81, 0x42, 0x61, + 0x3e, 0x1c, 0xc7, 0xc7, 0x27, 0xf2, 0x02, 0x8a, 0xe9, 0x0e, 0xb5, 0xaf, 0x70, 0x64, 0x2e, 0x6b, + 0xb2, 0x05, 0x4d, 0xd6, 0x8d, 0x21, 0x2f, 0x71, 0xe4, 0x3e, 0x99, 0xe0, 0xdd, 0x09, 0xfc, 0x25, + 0x8e, 0xec, 0x0f, 0x06, 0x94, 0x52, 0x7c, 0x64, 0xc0, 0x7d, 0x89, 0xe4, 0x10, 0x72, 0x77, 0x0a, + 0x49, 0xd3, 0xa8, 0x2c, 0xcd, 0x53, 0x31, 0x89, 0x89, 0x34, 0x50, 0x5c, 0xd1, 0xc1, 0x98, 0xe5, + 0x92, 0x66, 0xb9, 0xa2, 0x23, 0x9a, 0xe6, 0x1e, 0xac, 0xfb, 0xf8, 0x5e, 0xb5, 0x13, 0x3a, 0x65, + 0x34, 0xad, 0x7c, 0x14, 0x7e, 0x35, 0xd1, 0xca, 0xfe, 0x1a, 0x4a, 0xa7, 0x38, 0xc0, 0x79, 0x9d, + 0x9d, 0x6d, 0xc8, 0x7f, 0x19, 0x80, 0x3b, 0xd4, 0x6c, 0x9a, 0x10, 0x78, 0xe8, 0xd3, 0x21, 0xc6, + 0x65, 0xf4, 0xff, 0xa4, 0x02, 0xb9, 0x2e, 0x4a, 0x4f, 0x30, 0xed, 0xac, 0x58, 0xf0, 0x64, 0x88, + 0x7c, 0x0b, 0xe0, 0x69, 0x67, 0x75, 0xdb, 0x54, 0x69, 0xe5, 0x73, 0x47, 0x56, 0x6d, 0xec, 0xde, + 0xda, 0xc4, 0xbd, 0xb5, 0xd6, 0xc4, 0xbd, 0xee, 0x4a, 0x8c, 0xae, 0x2b, 0x72, 0x06, 0x9b, 0xe9, + 0xc6, 0x48, 0x73, 0x59, 0x8b, 0x57, 0x9c, 0xea, 0xca, 0x6d, 0x23, 0x5c, 0x92, 0xea, 0x8d, 0x24, + 0x75, 0xc8, 0x4b, 0xc5, 0x85, 0xb6, 0x8c, 0xa2, 0x0a, 0xcd, 0x6c, 0xc5, 0xa8, 0xae, 0x1d, 0x95, + 0x67, 0xf4, 0xaf, 0x35, 0xc7, 0xa0, 0x66, 0x84, 0x71, 0x57, 0x65, 0xe2, 0x64, 0x7b, 0xb0, 0x9a, + 0xcc, 0x92, 0x32, 0x98, 0xcd, 0xd6, 0x4f, 0x6e, 0xfd, 0xac, 0xd1, 0x6c, 0xd5, 0x5b, 0x8d, 0xf6, + 0xeb, 0x1f, 0x9b, 0xaf, 0x1a, 0x27, 0xe7, 0x2f, 0xce, 0x1b, 0xa7, 0x85, 0x07, 0xc4, 0x82, 0xe2, + 0x54, 0xb6, 0xfe, 0xa6, 0x7e, 0x7e, 0x51, 0x3f, 0xbe, 0x68, 0x14, 0x0c, 0xb2, 0x05, 0x9f, 0x4d, + 0xe7, 0xdc, 0x93, 0xef, 0xce, 0xdf, 0x34, 0x4e, 0x0b, 0x19, 0x7b, 0x1f, 0xcc, 0xba, 0xf0, 0x2e, + 0xd9, 0xf5, 0x3d, 0x9a, 0xf5, 0x14, 0xac, 0xd7, 0x3e, 0xbd, 0x27, 0xfa, 0xe8, 0xaf, 0x65, 0xd8, + 0xb8, 0x43, 0x35, 0x51, 0x5c, 0x33, 0x0f, 0x49, 0x00, 0x85, 0xd9, 0xa9, 0x27, 0x63, 0x51, 0x16, + 0x2c, 0x03, 0x6b, 0xd6, 0xb2, 0xf6, 0xc1, 0xef, 0xff, 0xfc, 0xfb, 0x21, 0xf3, 0x95, 0xbd, 0x15, + 0x2d, 0x31, 0xe9, 0x5c, 0x1f, 0x76, 0x50, 0xd1, 0xc3, 0xc4, 0xba, 0x94, 0xcf, 0x13, 0xbb, 0x81, + 0x78, 0x90, 0x9f, 0xda, 0x0d, 0x64, 0x4b, 0x5f, 0x38, 0x6f, 0x5f, 0xa4, 0x6b, 0xed, 0xe9, 0x5a, + 0x15, 0xf2, 0xf9, 0xc2, 0x5a, 0xce, 0x2f, 0xac, 0xfb, 0x2b, 0xf1, 0x61, 0x6d, 0x7a, 0x0e, 0xc9, + 0xb6, 0xbe, 0x6a, 0xfe, 0xb2, 0xb1, 0xca, 0xf3, 0x93, 0xe3, 0xc9, 0xb5, 0xbf, 0xd0, 0x45, 0xb7, + 0xc9, 0x62, 0x82, 0x91, 0x8c, 0xb3, 0x23, 0x16, 0xcb, 0xb8, 0x60, 0xf2, 0xac, 0x62, 0x6a, 0x00, + 0x1a, 0xd1, 0x6e, 0x9f, 0x30, 0xdc, 0xff, 0x14, 0xc3, 0x1b, 0xd8, 0x48, 0x19, 0x85, 0xec, 0xe8, + 0x92, 0x8b, 0x0c, 0xb4, 0xb0, 0x66, 0x4d, 0xd7, 0xac, 0xda, 0x7b, 0x1f, 0xaf, 0xf9, 0x3c, 0xf6, + 0x1a, 0xf9, 0xcd, 0x80, 0xcd, 0x39, 0xce, 0x23, 0xbb, 0xba, 0xfc, 0x62, 0x4f, 0x2e, 0x7c, 0xc0, + 0x37, 0xfa, 0x01, 0xfb, 0x76, 0xf5, 0x13, 0x0f, 0x08, 0x27, 0x57, 0x1f, 0xff, 0x61, 0xfc, 0x59, + 0xff, 0xc1, 0x2d, 0xc3, 0xa3, 0x2e, 0xf6, 0x68, 0x38, 0x50, 0x64, 0x83, 0xac, 0x43, 0xde, 0xca, + 0xe9, 0x17, 0x44, 0xf3, 0x19, 0xca, 0xb7, 0xbb, 0xb0, 0x03, 0xd9, 0x63, 0xa4, 0x02, 0x05, 0xd9, + 0x7c, 0x9c, 0xb1, 0xf2, 0x34, 0x54, 0x97, 0x5c, 0xb0, 0x1b, 0xfd, 0xdd, 0xab, 0x64, 0x3a, 0xab, + 0x00, 0xb7, 0x80, 0x07, 0x6f, 0x9f, 0xf5, 0x99, 0xba, 0x0c, 0x3b, 0x35, 0x8f, 0x0f, 0x9d, 0xab, + 0xb0, 0x83, 0xbd, 0x01, 0x7f, 0xe7, 0x04, 0x2c, 0xc0, 0x01, 0xf3, 0x51, 0x3a, 0xc9, 0xcf, 0x79, + 0x9f, 0xb7, 0xbd, 0x01, 0x43, 0x5f, 0x75, 0xb2, 0x9a, 0xc9, 0xb3, 0xff, 0x03, 0x00, 0x00, 0xff, + 0xff, 0x0b, 0x8f, 0xfa, 0xad, 0x2a, 0x08, 0x00, 0x00, } diff --git a/backend/api/go_client/experiment.pb.gw.go b/backend/api/go_client/experiment.pb.gw.go index bae0d0e1a8d..43eb71f5bc5 100755 --- a/backend/api/go_client/experiment.pb.gw.go +++ b/backend/api/go_client/experiment.pb.gw.go @@ -130,6 +130,60 @@ func request_ExperimentService_DeleteExperiment_0(ctx context.Context, marshaler } +func request_ExperimentService_ArchiveExperiment_0(ctx context.Context, marshaler runtime.Marshaler, client ExperimentServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ArchiveExperimentRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := client.ArchiveExperiment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ExperimentService_UnarchiveExperiment_0(ctx context.Context, marshaler runtime.Marshaler, client ExperimentServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UnarchiveExperimentRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := client.UnarchiveExperiment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + // RegisterExperimentServiceHandlerFromEndpoint is same as RegisterExperimentServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterExperimentServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -248,6 +302,46 @@ func RegisterExperimentServiceHandlerClient(ctx context.Context, mux *runtime.Se }) + mux.Handle("POST", pattern_ExperimentService_ArchiveExperiment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ExperimentService_ArchiveExperiment_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ExperimentService_ArchiveExperiment_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_ExperimentService_UnarchiveExperiment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ExperimentService_UnarchiveExperiment_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ExperimentService_UnarchiveExperiment_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -259,6 +353,10 @@ var ( pattern_ExperimentService_ListExperiment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"apis", "v1beta1", "experiments"}, "")) pattern_ExperimentService_DeleteExperiment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"apis", "v1beta1", "experiments", "id"}, "")) + + pattern_ExperimentService_ArchiveExperiment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"apis", "v1beta1", "experiments", "id"}, "archive")) + + pattern_ExperimentService_UnarchiveExperiment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"apis", "v1beta1", "experiments", "id"}, "unarchive")) ) var ( @@ -269,4 +367,8 @@ var ( forward_ExperimentService_ListExperiment_0 = runtime.ForwardResponseMessage forward_ExperimentService_DeleteExperiment_0 = runtime.ForwardResponseMessage + + forward_ExperimentService_ArchiveExperiment_0 = runtime.ForwardResponseMessage + + forward_ExperimentService_UnarchiveExperiment_0 = runtime.ForwardResponseMessage ) diff --git a/backend/api/go_http_client/experiment_client/experiment_service/BUILD.bazel b/backend/api/go_http_client/experiment_client/experiment_service/BUILD.bazel index 6669641c518..2d5a4495fd2 100644 --- a/backend/api/go_http_client/experiment_client/experiment_service/BUILD.bazel +++ b/backend/api/go_http_client/experiment_client/experiment_service/BUILD.bazel @@ -3,6 +3,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = [ + "archive_experiment_parameters.go", + "archive_experiment_responses.go", "create_experiment_parameters.go", "create_experiment_responses.go", "delete_experiment_parameters.go", @@ -12,6 +14,8 @@ go_library( "get_experiment_responses.go", "list_experiment_parameters.go", "list_experiment_responses.go", + "unarchive_experiment_parameters.go", + "unarchive_experiment_responses.go", ], importpath = "github.com/kubeflow/pipelines/backend/api/go_http_client/experiment_client/experiment_service", visibility = ["//visibility:public"], diff --git a/backend/api/go_http_client/experiment_client/experiment_service/archive_experiment_parameters.go b/backend/api/go_http_client/experiment_client/experiment_service/archive_experiment_parameters.go new file mode 100644 index 00000000000..471e6a5bfc6 --- /dev/null +++ b/backend/api/go_http_client/experiment_client/experiment_service/archive_experiment_parameters.go @@ -0,0 +1,147 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by go-swagger; DO NOT EDIT. + +package experiment_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + + strfmt "github.com/go-openapi/strfmt" +) + +// NewArchiveExperimentParams creates a new ArchiveExperimentParams object +// with the default values initialized. +func NewArchiveExperimentParams() *ArchiveExperimentParams { + var () + return &ArchiveExperimentParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewArchiveExperimentParamsWithTimeout creates a new ArchiveExperimentParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewArchiveExperimentParamsWithTimeout(timeout time.Duration) *ArchiveExperimentParams { + var () + return &ArchiveExperimentParams{ + + timeout: timeout, + } +} + +// NewArchiveExperimentParamsWithContext creates a new ArchiveExperimentParams object +// with the default values initialized, and the ability to set a context for a request +func NewArchiveExperimentParamsWithContext(ctx context.Context) *ArchiveExperimentParams { + var () + return &ArchiveExperimentParams{ + + Context: ctx, + } +} + +// NewArchiveExperimentParamsWithHTTPClient creates a new ArchiveExperimentParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewArchiveExperimentParamsWithHTTPClient(client *http.Client) *ArchiveExperimentParams { + var () + return &ArchiveExperimentParams{ + HTTPClient: client, + } +} + +/*ArchiveExperimentParams contains all the parameters to send to the API endpoint +for the archive experiment operation typically these are written to a http.Request +*/ +type ArchiveExperimentParams struct { + + /*ID*/ + ID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the archive experiment params +func (o *ArchiveExperimentParams) WithTimeout(timeout time.Duration) *ArchiveExperimentParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the archive experiment params +func (o *ArchiveExperimentParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the archive experiment params +func (o *ArchiveExperimentParams) WithContext(ctx context.Context) *ArchiveExperimentParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the archive experiment params +func (o *ArchiveExperimentParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the archive experiment params +func (o *ArchiveExperimentParams) WithHTTPClient(client *http.Client) *ArchiveExperimentParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the archive experiment params +func (o *ArchiveExperimentParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithID adds the id to the archive experiment params +func (o *ArchiveExperimentParams) WithID(id string) *ArchiveExperimentParams { + o.SetID(id) + return o +} + +// SetID adds the id to the archive experiment params +func (o *ArchiveExperimentParams) SetID(id string) { + o.ID = id +} + +// WriteToRequest writes these params to a swagger request +func (o *ArchiveExperimentParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param id + if err := r.SetPathParam("id", o.ID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/backend/api/go_http_client/experiment_client/experiment_service/archive_experiment_responses.go b/backend/api/go_http_client/experiment_client/experiment_service/archive_experiment_responses.go new file mode 100644 index 00000000000..dcbe3ff58da --- /dev/null +++ b/backend/api/go_http_client/experiment_client/experiment_service/archive_experiment_responses.go @@ -0,0 +1,124 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by go-swagger; DO NOT EDIT. + +package experiment_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + + strfmt "github.com/go-openapi/strfmt" + + experiment_model "github.com/kubeflow/pipelines/backend/api/go_http_client/experiment_model" +) + +// ArchiveExperimentReader is a Reader for the ArchiveExperiment structure. +type ArchiveExperimentReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ArchiveExperimentReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + + case 200: + result := NewArchiveExperimentOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + + default: + result := NewArchiveExperimentDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewArchiveExperimentOK creates a ArchiveExperimentOK with default headers values +func NewArchiveExperimentOK() *ArchiveExperimentOK { + return &ArchiveExperimentOK{} +} + +/*ArchiveExperimentOK handles this case with default header values. + +A successful response. +*/ +type ArchiveExperimentOK struct { + Payload interface{} +} + +func (o *ArchiveExperimentOK) Error() string { + return fmt.Sprintf("[POST /apis/v1beta1/experiments/{id}:archive][%d] archiveExperimentOK %+v", 200, o.Payload) +} + +func (o *ArchiveExperimentOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewArchiveExperimentDefault creates a ArchiveExperimentDefault with default headers values +func NewArchiveExperimentDefault(code int) *ArchiveExperimentDefault { + return &ArchiveExperimentDefault{ + _statusCode: code, + } +} + +/*ArchiveExperimentDefault handles this case with default header values. + +ArchiveExperimentDefault archive experiment default +*/ +type ArchiveExperimentDefault struct { + _statusCode int + + Payload *experiment_model.APIStatus +} + +// Code gets the status code for the archive experiment default response +func (o *ArchiveExperimentDefault) Code() int { + return o._statusCode +} + +func (o *ArchiveExperimentDefault) Error() string { + return fmt.Sprintf("[POST /apis/v1beta1/experiments/{id}:archive][%d] ArchiveExperiment default %+v", o._statusCode, o.Payload) +} + +func (o *ArchiveExperimentDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(experiment_model.APIStatus) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/backend/api/go_http_client/experiment_client/experiment_service/experiment_service_client.go b/backend/api/go_http_client/experiment_client/experiment_service/experiment_service_client.go index c966f7f03d6..8544a203002 100644 --- a/backend/api/go_http_client/experiment_client/experiment_service/experiment_service_client.go +++ b/backend/api/go_http_client/experiment_client/experiment_service/experiment_service_client.go @@ -38,6 +38,35 @@ type Client struct { formats strfmt.Registry } +/* +ArchiveExperiment archives an experiment +*/ +func (a *Client) ArchiveExperiment(params *ArchiveExperimentParams, authInfo runtime.ClientAuthInfoWriter) (*ArchiveExperimentOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewArchiveExperimentParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "ArchiveExperiment", + Method: "POST", + PathPattern: "/apis/v1beta1/experiments/{id}:archive", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ArchiveExperimentReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + return result.(*ArchiveExperimentOK), nil + +} + /* CreateExperiment creates a new experiment */ @@ -154,6 +183,35 @@ func (a *Client) ListExperiment(params *ListExperimentParams, authInfo runtime.C } +/* +UnarchiveExperiment restores an archived experiment +*/ +func (a *Client) UnarchiveExperiment(params *UnarchiveExperimentParams, authInfo runtime.ClientAuthInfoWriter) (*UnarchiveExperimentOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewUnarchiveExperimentParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "UnarchiveExperiment", + Method: "POST", + PathPattern: "/apis/v1beta1/experiments/{id}:unarchive", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &UnarchiveExperimentReader{formats: a.formats}, + AuthInfo: authInfo, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + return result.(*UnarchiveExperimentOK), nil + +} + // SetTransport changes the transport on the client func (a *Client) SetTransport(transport runtime.ClientTransport) { a.transport = transport diff --git a/backend/api/go_http_client/experiment_client/experiment_service/unarchive_experiment_parameters.go b/backend/api/go_http_client/experiment_client/experiment_service/unarchive_experiment_parameters.go new file mode 100644 index 00000000000..297a2959eb7 --- /dev/null +++ b/backend/api/go_http_client/experiment_client/experiment_service/unarchive_experiment_parameters.go @@ -0,0 +1,147 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by go-swagger; DO NOT EDIT. + +package experiment_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + + strfmt "github.com/go-openapi/strfmt" +) + +// NewUnarchiveExperimentParams creates a new UnarchiveExperimentParams object +// with the default values initialized. +func NewUnarchiveExperimentParams() *UnarchiveExperimentParams { + var () + return &UnarchiveExperimentParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewUnarchiveExperimentParamsWithTimeout creates a new UnarchiveExperimentParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewUnarchiveExperimentParamsWithTimeout(timeout time.Duration) *UnarchiveExperimentParams { + var () + return &UnarchiveExperimentParams{ + + timeout: timeout, + } +} + +// NewUnarchiveExperimentParamsWithContext creates a new UnarchiveExperimentParams object +// with the default values initialized, and the ability to set a context for a request +func NewUnarchiveExperimentParamsWithContext(ctx context.Context) *UnarchiveExperimentParams { + var () + return &UnarchiveExperimentParams{ + + Context: ctx, + } +} + +// NewUnarchiveExperimentParamsWithHTTPClient creates a new UnarchiveExperimentParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewUnarchiveExperimentParamsWithHTTPClient(client *http.Client) *UnarchiveExperimentParams { + var () + return &UnarchiveExperimentParams{ + HTTPClient: client, + } +} + +/*UnarchiveExperimentParams contains all the parameters to send to the API endpoint +for the unarchive experiment operation typically these are written to a http.Request +*/ +type UnarchiveExperimentParams struct { + + /*ID*/ + ID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the unarchive experiment params +func (o *UnarchiveExperimentParams) WithTimeout(timeout time.Duration) *UnarchiveExperimentParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the unarchive experiment params +func (o *UnarchiveExperimentParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the unarchive experiment params +func (o *UnarchiveExperimentParams) WithContext(ctx context.Context) *UnarchiveExperimentParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the unarchive experiment params +func (o *UnarchiveExperimentParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the unarchive experiment params +func (o *UnarchiveExperimentParams) WithHTTPClient(client *http.Client) *UnarchiveExperimentParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the unarchive experiment params +func (o *UnarchiveExperimentParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithID adds the id to the unarchive experiment params +func (o *UnarchiveExperimentParams) WithID(id string) *UnarchiveExperimentParams { + o.SetID(id) + return o +} + +// SetID adds the id to the unarchive experiment params +func (o *UnarchiveExperimentParams) SetID(id string) { + o.ID = id +} + +// WriteToRequest writes these params to a swagger request +func (o *UnarchiveExperimentParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param id + if err := r.SetPathParam("id", o.ID); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/backend/api/go_http_client/experiment_client/experiment_service/unarchive_experiment_responses.go b/backend/api/go_http_client/experiment_client/experiment_service/unarchive_experiment_responses.go new file mode 100644 index 00000000000..0713fb7ec45 --- /dev/null +++ b/backend/api/go_http_client/experiment_client/experiment_service/unarchive_experiment_responses.go @@ -0,0 +1,124 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by go-swagger; DO NOT EDIT. + +package experiment_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + + strfmt "github.com/go-openapi/strfmt" + + experiment_model "github.com/kubeflow/pipelines/backend/api/go_http_client/experiment_model" +) + +// UnarchiveExperimentReader is a Reader for the UnarchiveExperiment structure. +type UnarchiveExperimentReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UnarchiveExperimentReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + + case 200: + result := NewUnarchiveExperimentOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + + default: + result := NewUnarchiveExperimentDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewUnarchiveExperimentOK creates a UnarchiveExperimentOK with default headers values +func NewUnarchiveExperimentOK() *UnarchiveExperimentOK { + return &UnarchiveExperimentOK{} +} + +/*UnarchiveExperimentOK handles this case with default header values. + +A successful response. +*/ +type UnarchiveExperimentOK struct { + Payload interface{} +} + +func (o *UnarchiveExperimentOK) Error() string { + return fmt.Sprintf("[POST /apis/v1beta1/experiments/{id}:unarchive][%d] unarchiveExperimentOK %+v", 200, o.Payload) +} + +func (o *UnarchiveExperimentOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewUnarchiveExperimentDefault creates a UnarchiveExperimentDefault with default headers values +func NewUnarchiveExperimentDefault(code int) *UnarchiveExperimentDefault { + return &UnarchiveExperimentDefault{ + _statusCode: code, + } +} + +/*UnarchiveExperimentDefault handles this case with default header values. + +UnarchiveExperimentDefault unarchive experiment default +*/ +type UnarchiveExperimentDefault struct { + _statusCode int + + Payload *experiment_model.APIStatus +} + +// Code gets the status code for the unarchive experiment default response +func (o *UnarchiveExperimentDefault) Code() int { + return o._statusCode +} + +func (o *UnarchiveExperimentDefault) Error() string { + return fmt.Sprintf("[POST /apis/v1beta1/experiments/{id}:unarchive][%d] UnarchiveExperiment default %+v", o._statusCode, o.Payload) +} + +func (o *UnarchiveExperimentDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(experiment_model.APIStatus) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/backend/api/go_http_client/experiment_model/BUILD.bazel b/backend/api/go_http_client/experiment_model/BUILD.bazel index 9cf2fe8f8ad..cf3f4b58f86 100644 --- a/backend/api/go_http_client/experiment_model/BUILD.bazel +++ b/backend/api/go_http_client/experiment_model/BUILD.bazel @@ -10,6 +10,7 @@ go_library( "api_resource_reference.go", "api_resource_type.go", "api_status.go", + "experiment_storage_state.go", "protobuf_any.go", ], importpath = "github.com/kubeflow/pipelines/backend/api/go_http_client/experiment_model", diff --git a/backend/api/go_http_client/experiment_model/api_experiment.go b/backend/api/go_http_client/experiment_model/api_experiment.go index 457a34ded31..3f7e7520537 100644 --- a/backend/api/go_http_client/experiment_model/api_experiment.go +++ b/backend/api/go_http_client/experiment_model/api_experiment.go @@ -49,6 +49,9 @@ type APIExperiment struct { // Optional input field. Specify which resource this run belongs to. // For Experiment, the only valid resource reference is a single Namespace. ResourceReferences []*APIResourceReference `json:"resource_references"` + + // storage state + StorageState ExperimentStorageState `json:"storage_state,omitempty"` } // Validate validates this api experiment @@ -63,6 +66,10 @@ func (m *APIExperiment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateStorageState(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -107,6 +114,22 @@ func (m *APIExperiment) validateResourceReferences(formats strfmt.Registry) erro return nil } +func (m *APIExperiment) validateStorageState(formats strfmt.Registry) error { + + if swag.IsZero(m.StorageState) { // not required + return nil + } + + if err := m.StorageState.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("storage_state") + } + return err + } + + return nil +} + // MarshalBinary interface implementation func (m *APIExperiment) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/backend/api/go_http_client/experiment_model/experiment_storage_state.go b/backend/api/go_http_client/experiment_model/experiment_storage_state.go new file mode 100644 index 00000000000..3d1bcad4c74 --- /dev/null +++ b/backend/api/go_http_client/experiment_model/experiment_storage_state.go @@ -0,0 +1,80 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by go-swagger; DO NOT EDIT. + +package experiment_model + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/validate" +) + +// ExperimentStorageState experiment storage state +// swagger:model ExperimentStorageState +type ExperimentStorageState string + +const ( + + // ExperimentStorageStateSTORAGESTATEUNSPECIFIED captures enum value "STORAGESTATE_UNSPECIFIED" + ExperimentStorageStateSTORAGESTATEUNSPECIFIED ExperimentStorageState = "STORAGESTATE_UNSPECIFIED" + + // ExperimentStorageStateSTORAGESTATEAVAILABLE captures enum value "STORAGESTATE_AVAILABLE" + ExperimentStorageStateSTORAGESTATEAVAILABLE ExperimentStorageState = "STORAGESTATE_AVAILABLE" + + // ExperimentStorageStateSTORAGESTATEARCHIVED captures enum value "STORAGESTATE_ARCHIVED" + ExperimentStorageStateSTORAGESTATEARCHIVED ExperimentStorageState = "STORAGESTATE_ARCHIVED" +) + +// for schema +var experimentStorageStateEnum []interface{} + +func init() { + var res []ExperimentStorageState + if err := json.Unmarshal([]byte(`["STORAGESTATE_UNSPECIFIED","STORAGESTATE_AVAILABLE","STORAGESTATE_ARCHIVED"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + experimentStorageStateEnum = append(experimentStorageStateEnum, v) + } +} + +func (m ExperimentStorageState) validateExperimentStorageStateEnum(path, location string, value ExperimentStorageState) error { + if err := validate.Enum(path, location, value, experimentStorageStateEnum); err != nil { + return err + } + return nil +} + +// Validate validates this experiment storage state +func (m ExperimentStorageState) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateExperimentStorageStateEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/backend/api/swagger/experiment.swagger.json b/backend/api/swagger/experiment.swagger.json index 3c743b970f2..8c5976150a1 100644 --- a/backend/api/swagger/experiment.swagger.json +++ b/backend/api/swagger/experiment.swagger.json @@ -183,9 +183,80 @@ "ExperimentService" ] } + }, + "/apis/v1beta1/experiments/{id}:archive": { + "post": { + "summary": "Archive an experiment.", + "operationId": "ArchiveExperiment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/apiStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ExperimentService" + ] + } + }, + "/apis/v1beta1/experiments/{id}:unarchive": { + "post": { + "summary": "Restore an archived experiment.", + "operationId": "UnarchiveExperiment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/apiStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ExperimentService" + ] + } } }, "definitions": { + "ExperimentStorageState": { + "type": "string", + "enum": [ + "STORAGESTATE_UNSPECIFIED", + "STORAGESTATE_AVAILABLE", + "STORAGESTATE_ARCHIVED" + ], + "default": "STORAGESTATE_UNSPECIFIED" + }, "apiExperiment": { "type": "object", "properties": { @@ -212,6 +283,9 @@ "$ref": "#/definitions/apiResourceReference" }, "description": "Optional input field. Specify which resource this run belongs to.\nFor Experiment, the only valid resource reference is a single Namespace." + }, + "storage_state": { + "$ref": "#/definitions/ExperimentStorageState" } } }, diff --git a/backend/api/swagger/kfp_api_single_file.swagger.json b/backend/api/swagger/kfp_api_single_file.swagger.json index 5a187e048b3..25b4c212c60 100644 --- a/backend/api/swagger/kfp_api_single_file.swagger.json +++ b/backend/api/swagger/kfp_api_single_file.swagger.json @@ -1163,6 +1163,68 @@ ] } }, + "/apis/v1beta1/experiments/{id}:archive": { + "post": { + "summary": "Archive an experiment.", + "operationId": "ArchiveExperiment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/apiStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ExperimentService" + ] + } + }, + "/apis/v1beta1/experiments/{id}:unarchive": { + "post": { + "summary": "Restore an archived experiment.", + "operationId": "UnarchiveExperiment", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/apiStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ExperimentService" + ] + } + }, "/apis/v1beta1/pipelines/upload": { "post": { "operationId": "UploadPipeline", @@ -1876,6 +1938,15 @@ } } }, + "ExperimentStorageState": { + "type": "string", + "enum": [ + "STORAGESTATE_UNSPECIFIED", + "STORAGESTATE_AVAILABLE", + "STORAGESTATE_ARCHIVED" + ], + "default": "STORAGESTATE_UNSPECIFIED" + }, "apiExperiment": { "type": "object", "properties": { @@ -1902,6 +1973,9 @@ "$ref": "#/definitions/apiResourceReference" }, "description": "Optional input field. Specify which resource this run belongs to.\nFor Experiment, the only valid resource reference is a single Namespace." + }, + "storage_state": { + "$ref": "#/definitions/ExperimentStorageState" } } }, diff --git a/backend/src/apiserver/model/experiment.go b/backend/src/apiserver/model/experiment.go index efd369cf39b..40bdc27c6b8 100644 --- a/backend/src/apiserver/model/experiment.go +++ b/backend/src/apiserver/model/experiment.go @@ -6,6 +6,7 @@ type Experiment struct { Description string `gorm:"column:Description; not null"` CreatedAtInSec int64 `gorm:"column:CreatedAtInSec; not null"` Namespace string `gorm:"column:Namespace; not null; unique_index:idx_name_namespace"` + StorageState string `gorm:"column:StorageState; not null;"` } func (e Experiment) GetValueOfPrimaryKey() string { @@ -27,11 +28,12 @@ func (e *Experiment) DefaultSortField() string { } var experimentAPIToModelFieldMap = map[string]string{ - "id": "UUID", - "name": "Name", - "created_at": "CreatedAtInSec", - "description": "Description", - "namespace": "Namespace", + "id": "UUID", + "name": "Name", + "created_at": "CreatedAtInSec", + "description": "Description", + "namespace": "Namespace", + "storage_state": "StorageState", } // APIToModelFieldMap returns a map from API names to field names for model diff --git a/backend/src/apiserver/resource/resource_manager.go b/backend/src/apiserver/resource/resource_manager.go index 411fb483411..7c087b6917c 100644 --- a/backend/src/apiserver/resource/resource_manager.go +++ b/backend/src/apiserver/resource/resource_manager.go @@ -135,6 +135,52 @@ func (r *ResourceManager) DeleteExperiment(experimentID string) error { return r.experimentStore.DeleteExperiment(experimentID) } +func (r *ResourceManager) ArchiveExperiment(experimentId string) error { + // To archive an experiment + // (1) update our persistent agent to disable CRDs of jobs in experiment + // (2) update database to + // (2.1) archive experiemnts + // (2.2) archive runs + // (2.3) disable jobs + opts, err := list.NewOptions(&model.Job{}, 50, "name", nil) + if err != nil { + return util.NewInternalServerError(err, + "Failed to create list jobs options when archiving experiment. ") + } + for { + jobs, _, newToken, err := r.jobStore.ListJobs(&common.FilterContext{ + ReferenceKey: &common.ReferenceKey{Type: common.Experiment, ID: experimentId}}, opts) + if err != nil { + return util.NewInternalServerError(err, + "Failed to list jobs of to-be-archived experiment. expID: %v", experimentId) + } + for _, job := range jobs { + _, err = r.getScheduledWorkflowClient(job.Namespace).Patch( + job.Name, + types.MergePatchType, + []byte(fmt.Sprintf(`{"spec":{"enabled":%s}}`, strconv.FormatBool(false)))) + if err != nil { + return util.NewInternalServerError(err, + "Failed to disable job CRD. jobID: %v", job.UUID) + } + } + if newToken == "" { + break + } else { + opts, err = list.NewOptionsFromToken(newToken, 50) + if err != nil { + return util.NewInternalServerError(err, + "Failed to create list jobs options from page token when archiving experiment. ") + } + } + } + return r.experimentStore.ArchiveExperiment(experimentId) +} + +func (r *ResourceManager) UnarchiveExperiment(experimentId string) error { + return r.experimentStore.UnarchiveExperiment(experimentId) +} + func (r *ResourceManager) ListPipelines(opts *list.Options) ( pipelines []*model.Pipeline, total_size int, nextPageToken string, err error) { return r.pipelineStore.ListPipelines(opts) diff --git a/backend/src/apiserver/resource/resource_manager_test.go b/backend/src/apiserver/resource/resource_manager_test.go index 21d90985b12..99cf278dce9 100644 --- a/backend/src/apiserver/resource/resource_manager_test.go +++ b/backend/src/apiserver/resource/resource_manager_test.go @@ -2337,6 +2337,7 @@ func TestCreateDefaultExperiment(t *testing.T) { Name: "Default", Description: "All runs created without specifying an experiment will be grouped here.", Namespace: "", + StorageState: "STORAGESTATE_AVAILABLE", } assert.Equal(t, expectedExperiment, experiment) } @@ -2360,6 +2361,7 @@ func TestCreateDefaultExperiment_MultiUser(t *testing.T) { Name: "Default", Description: "All runs created without specifying an experiment will be grouped here.", Namespace: "", + StorageState: "STORAGESTATE_AVAILABLE", } assert.Equal(t, expectedExperiment, experiment) } diff --git a/backend/src/apiserver/server/api_converter.go b/backend/src/apiserver/server/api_converter.go index 3c664452491..9df33965b4f 100644 --- a/backend/src/apiserver/server/api_converter.go +++ b/backend/src/apiserver/server/api_converter.go @@ -44,6 +44,7 @@ func ToApiExperiment(experiment *model.Experiment) *api.Experiment { Description: experiment.Description, CreatedAt: ×tamp.Timestamp{Seconds: experiment.CreatedAtInSec}, ResourceReferences: resourceReferences, + StorageState: api.Experiment_StorageState(api.Experiment_StorageState_value[experiment.StorageState]), } } diff --git a/backend/src/apiserver/server/api_converter_test.go b/backend/src/apiserver/server/api_converter_test.go index bcde13b57bf..8603a355237 100644 --- a/backend/src/apiserver/server/api_converter_test.go +++ b/backend/src/apiserver/server/api_converter_test.go @@ -524,3 +524,38 @@ func TestToApiResourceReferences(t *testing.T) { } assert.Equal(t, expectedApiResourceReferences, toApiResourceReferences(resourceReferences)) } + +func TestToApiExperiments(t *testing.T) { + exp1 := &model.Experiment{ + UUID: "exp1", + CreatedAtInSec: 1, + Name: "experiment1", + Description: "My name is experiment1", + StorageState: "STORAGESTATE_AVAILABLE", + } + exp2 := &model.Experiment{ + UUID: "exp2", + CreatedAtInSec: 2, + Name: "experiment2", + Description: "My name is experiment2", + StorageState: "STORAGESTATE_ARCHIVED", + } + apiExps := ToApiExperiments([]*model.Experiment{exp1, exp2}) + expectedApiExps := []*api.Experiment{ + { + Id: "exp1", + Name: "experiment1", + Description: "My name is experiment1", + CreatedAt: ×tamp.Timestamp{Seconds: 1}, + StorageState: api.Experiment_StorageState(api.Experiment_StorageState_value["STORAGESTATE_AVAILABLE"]), + }, + { + Id: "exp2", + Name: "experiment2", + Description: "My name is experiment2", + CreatedAt: ×tamp.Timestamp{Seconds: 2}, + StorageState: api.Experiment_StorageState(api.Experiment_StorageState_value["STORAGESTATE_ARCHIVED"]), + }, + } + assert.Equal(t, expectedApiExps, apiExps) +} diff --git a/backend/src/apiserver/server/experiment_server.go b/backend/src/apiserver/server/experiment_server.go index f0e46974dfc..0fb53e02a5c 100644 --- a/backend/src/apiserver/server/experiment_server.go +++ b/backend/src/apiserver/server/experiment_server.go @@ -148,6 +148,30 @@ func (s *ExperimentServer) canAccessExperiment(ctx context.Context, experimentID return nil } +func (s *ExperimentServer) ArchiveExperiment(ctx context.Context, request *api.ArchiveExperimentRequest) (*empty.Empty, error) { + err := s.canAccessExperiment(ctx, request.Id) + if err != nil { + return nil, util.Wrap(err, "Failed to authorize the requests.") + } + err = s.resourceManager.ArchiveExperiment(request.Id) + if err != nil { + return nil, err + } + return &empty.Empty{}, nil +} + +func (s *ExperimentServer) UnarchiveExperiment(ctx context.Context, request *api.UnarchiveExperimentRequest) (*empty.Empty, error) { + err := s.canAccessExperiment(ctx, request.Id) + if err != nil { + return nil, util.Wrap(err, "Failed to authorize the requests.") + } + err = s.resourceManager.UnarchiveExperiment(request.Id) + if err != nil { + return nil, err + } + return &empty.Empty{}, nil +} + func NewExperimentServer(resourceManager *resource.ResourceManager) *ExperimentServer { return &ExperimentServer{resourceManager: resourceManager} } diff --git a/backend/src/apiserver/server/experiment_server_test.go b/backend/src/apiserver/server/experiment_server_test.go index 9ed7f1ce45e..ff699ccd272 100644 --- a/backend/src/apiserver/server/experiment_server_test.go +++ b/backend/src/apiserver/server/experiment_server_test.go @@ -26,10 +26,11 @@ func TestCreateExperiment(t *testing.T) { result, err := server.CreateExperiment(nil, &api.CreateExperimentRequest{Experiment: experiment}) assert.Nil(t, err) expectedExperiment := &api.Experiment{ - Id: resource.DefaultFakeUUID, - Name: "ex1", - Description: "first experiment", - CreatedAt: ×tamp.Timestamp{Seconds: 1}, + Id: resource.DefaultFakeUUID, + Name: "ex1", + Description: "first experiment", + CreatedAt: ×tamp.Timestamp{Seconds: 1}, + StorageState: api.Experiment_STORAGESTATE_AVAILABLE, } assert.Equal(t, expectedExperiment, result) } @@ -102,6 +103,7 @@ func TestCreateExperiment_Multiuser(t *testing.T) { Description: "first experiment", CreatedAt: ×tamp.Timestamp{Seconds: 1}, ResourceReferences: resourceReferences, + StorageState: api.Experiment_STORAGESTATE_AVAILABLE, } assert.Equal(t, expectedExperiment, result) } @@ -116,10 +118,11 @@ func TestGetExperiment(t *testing.T) { assert.Nil(t, err) result, err := server.GetExperiment(nil, &api.GetExperimentRequest{Id: createResult.Id}) expectedExperiment := &api.Experiment{ - Id: createResult.Id, - Name: "ex1", - Description: "first experiment", - CreatedAt: ×tamp.Timestamp{Seconds: 1}, + Id: createResult.Id, + Name: "ex1", + Description: "first experiment", + CreatedAt: ×tamp.Timestamp{Seconds: 1}, + StorageState: api.Experiment_STORAGESTATE_AVAILABLE, } assert.Equal(t, expectedExperiment, result) } @@ -185,6 +188,7 @@ func TestGetExperiment_Multiuser(t *testing.T) { Description: "first experiment", CreatedAt: ×tamp.Timestamp{Seconds: 1}, ResourceReferences: resourceReferences, + StorageState: api.Experiment_STORAGESTATE_AVAILABLE, } assert.Equal(t, expectedExperiment, result) } @@ -199,10 +203,11 @@ func TestListExperiment(t *testing.T) { assert.Nil(t, err) result, err := server.ListExperiment(nil, &api.ListExperimentsRequest{}) expectedExperiment := []*api.Experiment{{ - Id: createResult.Id, - Name: "ex1", - Description: "first experiment", - CreatedAt: ×tamp.Timestamp{Seconds: 1}, + Id: createResult.Id, + Name: "ex1", + Description: "first experiment", + CreatedAt: ×tamp.Timestamp{Seconds: 1}, + StorageState: api.Experiment_STORAGESTATE_AVAILABLE, }} assert.Equal(t, expectedExperiment, result.Experiments) } @@ -291,6 +296,7 @@ func TestListExperiment_Multiuser(t *testing.T) { Description: "first experiment", CreatedAt: ×tamp.Timestamp{Seconds: 1}, ResourceReferences: resourceReferences, + StorageState: api.Experiment_STORAGESTATE_AVAILABLE, }}, }, { @@ -490,3 +496,74 @@ func TestValidateCreateExperimentRequest_Multiuser(t *testing.T) { } } } + +func TestArchiveAndUnarchiveExperiment(t *testing.T) { + // Create experiment and runs/jobs under it. + clients, manager, experiment := initWithExperimentAndPipelineVersion(t) + defer clients.Close() + runServer := NewRunServer(manager) + run1 := &api.Run{ + Name: "run1", + ResourceReferences: validReferencesOfExperimentAndPipelineVersion, + } + err := runServer.validateCreateRunRequest(&api.CreateRunRequest{Run: run1}) + assert.Nil(t, err) + _, err = runServer.CreateRun(nil, &api.CreateRunRequest{Run: run1}) + assert.Nil(t, err) + clients.UpdateUUID(util.NewFakeUUIDGeneratorOrFatal(resource.FakeUUIDOne, nil)) + manager = resource.NewResourceManager(clients) + runServer = NewRunServer(manager) + run2 := &api.Run{ + Name: "run2", + ResourceReferences: validReferencesOfExperimentAndPipelineVersion, + } + err = runServer.validateCreateRunRequest(&api.CreateRunRequest{Run: run2}) + assert.Nil(t, err) + _, err = runServer.CreateRun(nil, &api.CreateRunRequest{Run: run2}) + assert.Nil(t, err) + clients.UpdateUUID(util.NewFakeUUIDGeneratorOrFatal(resource.DefaultFakeUUID, nil)) + manager = resource.NewResourceManager(clients) + jobServer := NewJobServer(manager) + job1 := &api.Job{ + Name: "name1", + Enabled: true, + MaxConcurrency: 1, + Trigger: &api.Trigger{ + Trigger: &api.Trigger_CronSchedule{CronSchedule: &api.CronSchedule{ + StartTime: ×tamp.Timestamp{Seconds: 1}, + Cron: "1 * * * *", + }}}, + ResourceReferences: validReferencesOfExperimentAndPipelineVersion, + } + err = jobServer.validateCreateJobRequest(&api.CreateJobRequest{Job: job1}) + assert.Nil(t, err) + _, err = jobServer.CreateJob(nil, &api.CreateJobRequest{Job: job1}) + assert.Nil(t, err) + + // Archive the experiment and thus all runs under it. + experimentServer := NewExperimentServer(manager) + _, err = experimentServer.ArchiveExperiment(nil, &api.ArchiveExperimentRequest{Id: experiment.UUID}) + assert.Nil(t, err) + result, err := experimentServer.GetExperiment(nil, &api.GetExperimentRequest{Id: experiment.UUID}) + assert.Equal(t, api.Experiment_STORAGESTATE_ARCHIVED, result.StorageState) + runs, err := runServer.ListRuns(nil, &api.ListRunsRequest{ResourceReferenceKey: &api.ResourceKey{Id: experiment.UUID, Type: api.ResourceType_EXPERIMENT}}) + assert.Equal(t, 2, len(runs.Runs)) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED, runs.Runs[0].StorageState) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED, runs.Runs[1].StorageState) + jobs, err := jobServer.ListJobs(nil, &api.ListJobsRequest{ResourceReferenceKey: &api.ResourceKey{Id: experiment.UUID, Type: api.ResourceType_EXPERIMENT}}) + assert.Equal(t, 1, len(jobs.Jobs)) + assert.Equal(t, false, jobs.Jobs[0].Enabled) + + // Unarchive the experiment and thus all runs under it. + _, err = experimentServer.UnarchiveExperiment(nil, &api.UnarchiveExperimentRequest{Id: experiment.UUID}) + assert.Nil(t, err) + result, err = experimentServer.GetExperiment(nil, &api.GetExperimentRequest{Id: experiment.UUID}) + assert.Equal(t, api.Experiment_STORAGESTATE_AVAILABLE, result.StorageState) + runs, err = runServer.ListRuns(nil, &api.ListRunsRequest{ResourceReferenceKey: &api.ResourceKey{Id: experiment.UUID, Type: api.ResourceType_EXPERIMENT}}) + assert.Equal(t, 2, len(runs.Runs)) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED, runs.Runs[0].StorageState) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED, runs.Runs[1].StorageState) + jobs, err = jobServer.ListJobs(nil, &api.ListJobsRequest{ResourceReferenceKey: &api.ResourceKey{Id: experiment.UUID, Type: api.ResourceType_EXPERIMENT}}) + assert.Equal(t, 1, len(jobs.Jobs)) + assert.Equal(t, false, jobs.Jobs[0].Enabled) +} diff --git a/backend/src/apiserver/storage/experiment_store.go b/backend/src/apiserver/storage/experiment_store.go index cd70ebe930e..bc3ed2b1d9d 100644 --- a/backend/src/apiserver/storage/experiment_store.go +++ b/backend/src/apiserver/storage/experiment_store.go @@ -7,6 +7,7 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/golang/glog" + api "github.com/kubeflow/pipelines/backend/api/go_client" "github.com/kubeflow/pipelines/backend/src/apiserver/common" "github.com/kubeflow/pipelines/backend/src/apiserver/list" "github.com/kubeflow/pipelines/backend/src/apiserver/model" @@ -18,6 +19,8 @@ type ExperimentStoreInterface interface { GetExperiment(uuid string) (*model.Experiment, error) CreateExperiment(*model.Experiment) (*model.Experiment, error) DeleteExperiment(uuid string) error + ArchiveExperiment(expId string) error + UnarchiveExperiment(expId string) error } type ExperimentStore struct { @@ -132,19 +135,25 @@ func (s *ExperimentStore) GetExperiment(uuid string) (*model.Experiment, error) func (s *ExperimentStore) scanRows(rows *sql.Rows) ([]*model.Experiment, error) { var experiments []*model.Experiment for rows.Next() { - var uuid, name, description, namespace string + var uuid, name, description, namespace, storageState string var createdAtInSec int64 - err := rows.Scan(&uuid, &name, &description, &createdAtInSec, &namespace) + err := rows.Scan(&uuid, &name, &description, &createdAtInSec, &namespace, &storageState) if err != nil { return experiments, err } - experiments = append(experiments, &model.Experiment{ + experiment := &model.Experiment{ UUID: uuid, Name: name, Description: description, CreatedAtInSec: createdAtInSec, Namespace: namespace, - }) + StorageState: storageState, + } + // Since storage state is a field added after initial KFP release, it is possible that existing experiments don't have this field and we use AVAILABLE in that case. + if experiment.StorageState == "" { + experiment.StorageState = api.Experiment_STORAGESTATE_AVAILABLE.String() + } + experiments = append(experiments, experiment) } return experiments, nil } @@ -158,6 +167,15 @@ func (s *ExperimentStore) CreateExperiment(experiment *model.Experiment) (*model return nil, util.NewInternalServerError(err, "Failed to create an experiment id.") } newExperiment.UUID = id.String() + + if newExperiment.StorageState == "" { + // Default to available if not set. + newExperiment.StorageState = api.Experiment_STORAGESTATE_AVAILABLE.String() + } else if newExperiment.StorageState != api.Experiment_STORAGESTATE_AVAILABLE.String() && + newExperiment.StorageState != api.Experiment_STORAGESTATE_ARCHIVED.String() { + return nil, util.NewInvalidInputError("Invalid value for StorageState field: %q.", newExperiment.StorageState) + } + sql, args, err := sq. Insert("experiments"). SetMap(sq.Eq{ @@ -166,6 +184,7 @@ func (s *ExperimentStore) CreateExperiment(experiment *model.Experiment) (*model "Name": newExperiment.Name, "Description": newExperiment.Description, "Namespace": newExperiment.Namespace, + "StorageState": newExperiment.StorageState, }). ToSql() if err != nil { @@ -217,6 +236,151 @@ func (s *ExperimentStore) DeleteExperiment(id string) error { return nil } +func (s *ExperimentStore) ArchiveExperiment(expId string) error { + // ArchiveExperiment results in + // 1. The experiment getting archived + // 2. All the runs in the experiment getting archived no matter what previous storage state they are in + sql, args, err := sq. + Update("experiments"). + SetMap(sq.Eq{ + "StorageState": api.Experiment_STORAGESTATE_ARCHIVED.String(), + }). + Where(sq.Eq{"UUID": expId}). + ToSql() + if err != nil { + return util.NewInternalServerError(err, + "Failed to create query to archive experiment %s. error: '%v'", expId, err.Error()) + } + + // TODO(jingzhang36): use inner join to replace nested query for better performance. + filteredRunsSql, filteredRunsArgs, err := sq.Select("ResourceUUID"). + From("resource_references as rf"). + Where(sq.And{ + sq.Eq{"rf.ResourceType": common.Run}, + sq.Eq{"rf.ReferenceUUID": expId}, + sq.Eq{"rf.ReferenceType": common.Experiment}}).ToSql() + if err != nil { + return util.NewInternalServerError(err, + "Failed to create query to filter the runs in an experiment %s. error: '%v'", expId, err.Error()) + } + updateRunsSql, updateRunsArgs, err := sq. + Update("run_details"). + SetMap(sq.Eq{ + "StorageState": api.Run_STORAGESTATE_ARCHIVED.String(), + }). + Where(fmt.Sprintf("UUID in (%s)", filteredRunsSql), filteredRunsArgs...). + ToSql() + if err != nil { + return util.NewInternalServerError(err, + "Failed to create query to archive the runs in an experiment %s. error: '%v'", expId, err.Error()) + } + + updateRunsWithExperimentUUIDSql, updateRunsWithExperimentUUIDArgs, err := sq. + Update("run_details"). + SetMap(sq.Eq{ + "StorageState": api.Run_STORAGESTATE_ARCHIVED.String(), + }). + Where(sq.Eq{"ExperimentUUID": expId}). + Where(sq.NotEq{"StorageState": api.Run_STORAGESTATE_ARCHIVED.String()}). + ToSql() + if err != nil { + return util.NewInternalServerError(err, + "Failed to create query to archive the runs in an experiment %s. error: '%v'", expId, err.Error()) + } + + // TODO(jingzhang36): use inner join to replace nested query for better performance. + filteredJobsSql, filteredJobsArgs, err := sq.Select("ResourceUUID"). + From("resource_references as rf"). + Where(sq.And{ + sq.Eq{"rf.ResourceType": common.Job}, + sq.Eq{"rf.ReferenceUUID": expId}, + sq.Eq{"rf.ReferenceType": common.Experiment}}).ToSql() + if err != nil { + return util.NewInternalServerError(err, + "Failed to create query to filter the jobs in an experiment %s. error: '%v'", expId, err.Error()) + } + now := s.time.Now().Unix() + updateJobsSql, updateJobsArgs, err := sq. + Update("jobs"). + SetMap(sq.Eq{ + "Enabled": false, + "UpdatedAtInSec": now}). + Where(sq.Eq{"Enabled": true}). + Where(fmt.Sprintf("UUID in (%s)", filteredJobsSql), filteredJobsArgs...). + ToSql() + if err != nil { + return util.NewInternalServerError(err, + "Failed to create query to archive the jobs in an experiment %s. error: '%v'", expId, err.Error()) + } + + // In a single transaction, we update experiments, run_details and jobs tables. + tx, err := s.db.Begin() + if err != nil { + return util.NewInternalServerError(err, "Failed to create a new transaction to archive an experiment.") + } + + _, err = tx.Exec(sql, args...) + if err != nil { + tx.Rollback() + return util.NewInternalServerError(err, + "Failed to archive experiment %s. error: '%v'", expId, err.Error()) + } + + _, err = tx.Exec(updateRunsSql, updateRunsArgs...) + if err != nil { + tx.Rollback() + return util.NewInternalServerError(err, + "Failed to archive runs with experiment reference being %s. error: '%v'", expId, err.Error()) + } + + _, err = tx.Exec(updateRunsWithExperimentUUIDSql, updateRunsWithExperimentUUIDArgs...) + if err != nil { + tx.Rollback() + return util.NewInternalServerError(err, + "Failed to archive runs with ExperimentUUID being %s. error: '%v'", expId, err.Error()) + } + + _, err = tx.Exec(updateJobsSql, updateJobsArgs...) + if err != nil { + tx.Rollback() + return util.NewInternalServerError(err, + "Failed to disable all jobs in an experiment %s. error: '%v'", expId, err.Error()) + } + + err = tx.Commit() + if err != nil { + tx.Rollback() + return util.NewInternalServerError(err, "Failed to archive an experiment %s and its runs", expId) + } + + return nil +} + +func (s *ExperimentStore) UnarchiveExperiment(expId string) error { + // UnarchiveExperiment results in + // 1. The experiment getting unarchived + // 2. All the archived runs and disabled jobs will stay archived + sql, args, err := sq. + Update("experiments"). + SetMap(sq.Eq{ + "StorageState": api.Experiment_STORAGESTATE_AVAILABLE.String(), + }). + Where(sq.Eq{"UUID": expId}). + ToSql() + if err != nil { + return util.NewInternalServerError(err, + "Failed to create query to unarchive experiment %s. error: '%v'", expId, err.Error()) + } + + _, err = s.db.Exec(sql, args...) + if err != nil { + return util.NewInternalServerError(err, + "Failed to unarchive experiment %s. error: '%v'", expId, err.Error()) + } + + return nil +} + // factory function for experiment store func NewExperimentStore(db *DB, time util.TimeInterface, uuid util.UUIDGeneratorInterface) *ExperimentStore { return &ExperimentStore{ diff --git a/backend/src/apiserver/storage/experiment_store_test.go b/backend/src/apiserver/storage/experiment_store_test.go index 8148a05bac3..aa0fbf02964 100644 --- a/backend/src/apiserver/storage/experiment_store_test.go +++ b/backend/src/apiserver/storage/experiment_store_test.go @@ -50,12 +50,14 @@ func TestListExperiments_Pagination(t *testing.T) { CreatedAtInSec: 1, Name: "experiment1", Description: "My name is experiment1", + StorageState: "STORAGESTATE_AVAILABLE", } expectedExperiment4 := &model.Experiment{ UUID: fakeIDFour, CreatedAtInSec: 4, Name: "experiment2", Description: "My name is experiment2", + StorageState: "STORAGESTATE_AVAILABLE", } experimentsExpected := []*model.Experiment{expectedExperiment1, expectedExperiment4} opts, err := list.NewOptions(&model.Experiment{}, 2, "name", nil) @@ -73,12 +75,14 @@ func TestListExperiments_Pagination(t *testing.T) { CreatedAtInSec: 2, Name: "experiment3", Description: "My name is experiment3", + StorageState: "STORAGESTATE_AVAILABLE", } expectedExperiment3 := &model.Experiment{ UUID: fakeIDThree, CreatedAtInSec: 3, Name: "experiment4", Description: "My name is experiment4", + StorageState: "STORAGESTATE_AVAILABLE", } experimentsExpected2 := []*model.Experiment{expectedExperiment2, expectedExperiment3} @@ -109,12 +113,14 @@ func TestListExperiments_Pagination_Descend(t *testing.T) { CreatedAtInSec: 2, Name: "experiment3", Description: "My name is experiment3", + StorageState: "STORAGESTATE_AVAILABLE", } expectedExperiment3 := &model.Experiment{ UUID: fakeIDThree, CreatedAtInSec: 3, Name: "experiment4", Description: "My name is experiment4", + StorageState: "STORAGESTATE_AVAILABLE", } experimentsExpected := []*model.Experiment{expectedExperiment3, expectedExperiment2} @@ -132,12 +138,14 @@ func TestListExperiments_Pagination_Descend(t *testing.T) { CreatedAtInSec: 1, Name: "experiment1", Description: "My name is experiment1", + StorageState: "STORAGESTATE_AVAILABLE", } expectedExperiment4 := &model.Experiment{ UUID: fakeIDFour, CreatedAtInSec: 4, Name: "experiment2", Description: "My name is experiment2", + StorageState: "STORAGESTATE_AVAILABLE", } experimentsExpected2 := []*model.Experiment{expectedExperiment4, expectedExperiment1} @@ -161,6 +169,7 @@ func TestListExperiments_Pagination_LessThanPageSize(t *testing.T) { CreatedAtInSec: 1, Name: "experiment1", Description: "My name is experiment1", + StorageState: "STORAGESTATE_AVAILABLE", } experimentsExpected := []*model.Experiment{expectedExperiment1} @@ -196,6 +205,7 @@ func TestGetExperiment(t *testing.T) { CreatedAtInSec: 1, Name: "experiment1", Description: "My name is experiment1", + StorageState: "STORAGESTATE_AVAILABLE", } experiment, err := experimentStore.GetExperiment(fakeID) @@ -232,6 +242,7 @@ func TestCreateExperiment(t *testing.T) { CreatedAtInSec: 1, Name: "experiment1", Description: "My name is experiment1", + StorageState: "STORAGESTATE_AVAILABLE", } experiment := createExperiment("experiment1") @@ -250,6 +261,7 @@ func TestCreateExperiment_DifferentNamespaces(t *testing.T) { Name: "experiment1", Description: "My name is experiment1", Namespace: "namespace1", + StorageState: "STORAGESTATE_AVAILABLE", } experiment := createExperimentInNamespace("experiment1", "namespace1") @@ -265,6 +277,7 @@ func TestCreateExperiment_DifferentNamespaces(t *testing.T) { Name: "experiment1", Description: "My name is experiment1", Namespace: "namespace2", + StorageState: "STORAGESTATE_AVAILABLE", } experiment, err = experimentStore.CreateExperiment(experiment) @@ -377,12 +390,14 @@ func TestListExperiments_Filtering(t *testing.T) { CreatedAtInSec: 2, Name: "experiment2", Description: "My name is experiment2", + StorageState: "STORAGESTATE_AVAILABLE", }, &model.Experiment{ UUID: fakeIDThree, CreatedAtInSec: 3, Name: "experiment3", Description: "My name is experiment3", + StorageState: "STORAGESTATE_AVAILABLE", }, } @@ -403,6 +418,7 @@ func TestListExperiments_Filtering(t *testing.T) { CreatedAtInSec: 4, Name: "experiment4", Description: "My name is experiment4", + StorageState: "STORAGESTATE_AVAILABLE", }, } @@ -412,3 +428,171 @@ func TestListExperiments_Filtering(t *testing.T) { assert.Equal(t, expected, experiments) assert.Equal(t, 3, total_size) } + +func TestArchiveExperiment_InternalError(t *testing.T) { + db := NewFakeDbOrFatal() + experimentStore := NewExperimentStore(db, util.NewFakeTimeForEpoch(), util.NewFakeUUIDGeneratorOrFatal(fakeID, nil)) + experimentStore.CreateExperiment(createExperiment("experiment1")) + db.Close() + + err := experimentStore.ArchiveExperiment(fakeID) + assert.Equal(t, codes.Internal, err.(*util.UserError).ExternalStatusCode(), + "Expected archive experiment to return internal error") +} + +func TestArchiveAndUnarchiveExperiment(t *testing.T) { + db := NewFakeDbOrFatal() + defer db.Close() + + // Initial state: 1 experiment and 2 runs in it. + // The experiment is unarchived. + // One run is archived and the other is not. + experimentStore := NewExperimentStore(db, util.NewFakeTimeForEpoch(), util.NewFakeUUIDGeneratorOrFatal(fakeID, nil)) + experimentStore.CreateExperiment(createExperiment("experiment1")) + runStore := NewRunStore(db, util.NewFakeTimeForEpoch()) + run1 := &model.RunDetail{ + Run: model.Run{ + UUID: "1", + Name: "run1", + DisplayName: "run1", + StorageState: api.Run_STORAGESTATE_AVAILABLE.String(), + Namespace: "n1", + CreatedAtInSec: 1, + ScheduledAtInSec: 1, + Conditions: "Running", + ExperimentUUID: fakeID, + ResourceReferences: []*model.ResourceReference{ + { + ResourceUUID: "1", ResourceType: common.Run, + ReferenceUUID: fakeID, ReferenceName: "experiment1", + ReferenceType: common.Experiment, Relationship: common.Creator, + }, + }, + }, + PipelineRuntime: model.PipelineRuntime{ + WorkflowRuntimeManifest: "workflow1", + }, + } + run2 := &model.RunDetail{ + Run: model.Run{ + UUID: "2", + Name: "run2", + DisplayName: "run2", + StorageState: api.Run_STORAGESTATE_ARCHIVED.String(), + Namespace: "n1", + CreatedAtInSec: 2, + ScheduledAtInSec: 2, + Conditions: "done", + ExperimentUUID: fakeID, + ResourceReferences: []*model.ResourceReference{ + { + ResourceUUID: "2", ResourceType: common.Run, + ReferenceUUID: fakeID, ReferenceName: "experiment1", + ReferenceType: common.Experiment, Relationship: common.Creator, + }, + }, + }, + PipelineRuntime: model.PipelineRuntime{ + WorkflowRuntimeManifest: "workflow1", + }, + } + runStore.CreateRun(run1) + runStore.CreateRun(run2) + jobStore := NewJobStore(db, util.NewFakeTimeForEpoch()) + job1 := &model.Job{ + UUID: "1", + DisplayName: "pp 1", + Name: "pp1", + Namespace: "n1", + Enabled: true, + Conditions: "ready", + Trigger: model.Trigger{ + PeriodicSchedule: model.PeriodicSchedule{ + PeriodicScheduleStartTimeInSec: util.Int64Pointer(1), + PeriodicScheduleEndTimeInSec: util.Int64Pointer(2), + IntervalSecond: util.Int64Pointer(3), + }, + }, + CreatedAtInSec: 1, + UpdatedAtInSec: 1, + ResourceReferences: []*model.ResourceReference{ + { + ResourceUUID: "1", ResourceType: common.Job, ReferenceUUID: fakeID, + ReferenceName: "experiment1", ReferenceType: common.Experiment, + Relationship: common.Owner, + }, + }, + } + job2 := &model.Job{ + UUID: "2", + DisplayName: "pp 2", + Name: "pp2", + Namespace: "n1", + Conditions: "ready", + Trigger: model.Trigger{ + CronSchedule: model.CronSchedule{ + CronScheduleStartTimeInSec: util.Int64Pointer(1), + CronScheduleEndTimeInSec: util.Int64Pointer(2), + Cron: util.StringPointer("1 * *"), + }, + }, + NoCatchup: true, + Enabled: false, + CreatedAtInSec: 2, + UpdatedAtInSec: 2, + ResourceReferences: []*model.ResourceReference{ + { + ResourceUUID: "2", ResourceType: common.Job, + ReferenceUUID: fakeID, ReferenceName: "experiment2", ReferenceType: common.Experiment, + Relationship: common.Owner, + }, + }, + } + jobStore.CreateJob(job1) + jobStore.CreateJob(job2) + + // Archive experiment and verify the experiment and two runs in it are all archived. + err := experimentStore.ArchiveExperiment(fakeID) + assert.Nil(t, err) + exp, err := experimentStore.GetExperiment(fakeID) + assert.Nil(t, err) + assert.Equal(t, api.Experiment_STORAGESTATE_ARCHIVED.String(), exp.StorageState) + opts, err := list.NewOptions(&model.Run{}, 10, "id", nil) + runs, total_run_size, _, err := runStore.ListRuns(&common.FilterContext{ReferenceKey: &common.ReferenceKey{Type: common.Experiment, ID: fakeID}}, opts) + assert.Nil(t, err) + assert.Equal(t, total_run_size, 2) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED.String(), runs[0].StorageState) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED.String(), runs[1].StorageState) + jobs, total_job_size, _, err := jobStore.ListJobs(&common.FilterContext{ReferenceKey: &common.ReferenceKey{Type: common.Experiment, ID: fakeID}}, opts) + assert.Nil(t, err) + assert.Equal(t, total_job_size, 2) + assert.Equal(t, false, jobs[0].Enabled) + assert.Equal(t, false, jobs[1].Enabled) + + // Unarchive the experiment, and verify the experiment is unarchived while two runs in it stay archived. + err = experimentStore.UnarchiveExperiment(fakeID) + assert.Nil(t, err) + exp, err = experimentStore.GetExperiment(fakeID) + assert.Nil(t, err) + assert.Equal(t, api.Experiment_STORAGESTATE_AVAILABLE.String(), exp.StorageState) + runs, total_run_size, _, err = runStore.ListRuns(&common.FilterContext{ReferenceKey: &common.ReferenceKey{Type: common.Experiment, ID: fakeID}}, opts) + assert.Nil(t, err) + assert.Equal(t, total_run_size, 2) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED.String(), runs[0].StorageState) + assert.Equal(t, api.Run_STORAGESTATE_ARCHIVED.String(), runs[1].StorageState) + jobs, total_job_size, _, err = jobStore.ListJobs(&common.FilterContext{ReferenceKey: &common.ReferenceKey{Type: common.Experiment, ID: fakeID}}, opts) + assert.Nil(t, err) + assert.Equal(t, total_job_size, 2) + assert.Equal(t, false, jobs[0].Enabled) + assert.Equal(t, false, jobs[1].Enabled) +} + +func TestUnarchiveExperiment_InternalError(t *testing.T) { + db := NewFakeDbOrFatal() + experimentStore := NewExperimentStore(db, util.NewFakeTimeForEpoch(), util.NewFakeUUIDGeneratorOrFatal(fakeID, nil)) + db.Close() + + err := experimentStore.UnarchiveExperiment(fakeID) + assert.Equal(t, codes.Internal, err.(*util.UserError).ExternalStatusCode(), + "Expected unarchive experiment to return internal error") +} diff --git a/backend/src/common/client/api_server/experiment_client.go b/backend/src/common/client/api_server/experiment_client.go index f246335797e..7080922b0b9 100644 --- a/backend/src/common/client/api_server/experiment_client.go +++ b/backend/src/common/client/api_server/experiment_client.go @@ -18,6 +18,8 @@ type ExperimentInterface interface { Get(params *params.GetExperimentParams) (*model.APIExperiment, error) List(params *params.ListExperimentParams) ([]*model.APIExperiment, int, string, error) ListAll(params *params.ListExperimentParams, maxResultSize int) ([]*model.APIExperiment, error) + Archive(params *params.ArchiveExperimentParams) error + Unarchive(params *params.UnarchiveExperimentParams) error } type ExperimentClient struct { @@ -164,3 +166,51 @@ func listAllForExperiment(client ExperimentInterface, parameters *params.ListExp return allResults, nil } + +func (c *ExperimentClient) Archive(parameters *params.ArchiveExperimentParams) error { + // Create context with timeout + ctx, cancel := context.WithTimeout(context.Background(), apiServerDefaultTimeout) + defer cancel() + + // Make service call + parameters.Context = ctx + _, err := c.apiClient.ExperimentService.ArchiveExperiment(parameters, PassThroughAuth) + + if err != nil { + if defaultError, ok := err.(*params.ArchiveExperimentDefault); ok { + err = CreateErrorFromAPIStatus(defaultError.Payload.Error, defaultError.Payload.Code) + } else { + err = CreateErrorCouldNotRecoverAPIStatus(err) + } + + return util.NewUserError(err, + fmt.Sprintf("Failed to archive experiments. Params: '%+v'", parameters), + fmt.Sprintf("Failed to archive experiments")) + } + + return nil +} + +func (c *ExperimentClient) Unarchive(parameters *params.UnarchiveExperimentParams) error { + // Create context with timeout + ctx, cancel := context.WithTimeout(context.Background(), apiServerDefaultTimeout) + defer cancel() + + // Make service call + parameters.Context = ctx + _, err := c.apiClient.ExperimentService.UnarchiveExperiment(parameters, PassThroughAuth) + + if err != nil { + if defaultError, ok := err.(*params.UnarchiveExperimentDefault); ok { + err = CreateErrorFromAPIStatus(defaultError.Payload.Error, defaultError.Payload.Code) + } else { + err = CreateErrorCouldNotRecoverAPIStatus(err) + } + + return util.NewUserError(err, + fmt.Sprintf("Failed to unarchive experiments. Params: '%+v'", parameters), + fmt.Sprintf("Failed to unarchive experiments")) + } + + return nil +} diff --git a/backend/src/common/client/api_server/experiment_client_fake.go b/backend/src/common/client/api_server/experiment_client_fake.go index 43f3779e8d8..d29eceef928 100644 --- a/backend/src/common/client/api_server/experiment_client_fake.go +++ b/backend/src/common/client/api_server/experiment_client_fake.go @@ -80,3 +80,11 @@ func (c *ExperimentClientFake) ListAll(params *experimentparams.ListExperimentPa maxResultSize int) ([]*experimentmodel.APIExperiment, error) { return listAllForExperiment(c, params, maxResultSize) } + +func (c *ExperimentClientFake) Archive(params *experimentparams.ArchiveExperimentParams) error { + return nil +} + +func (c *ExperimentClientFake) Unarchive(params *experimentparams.UnarchiveExperimentParams) error { + return nil +} diff --git a/backend/test/integration/experiment_api_test.go b/backend/test/integration/experiment_api_test.go index e9a90d22039..f01dffeda2e 100644 --- a/backend/test/integration/experiment_api_test.go +++ b/backend/test/integration/experiment_api_test.go @@ -8,6 +8,11 @@ import ( "github.com/golang/glog" params "github.com/kubeflow/pipelines/backend/api/go_http_client/experiment_client/experiment_service" "github.com/kubeflow/pipelines/backend/api/go_http_client/experiment_model" + jobParams "github.com/kubeflow/pipelines/backend/api/go_http_client/job_client/job_service" + "github.com/kubeflow/pipelines/backend/api/go_http_client/job_model" + uploadParams "github.com/kubeflow/pipelines/backend/api/go_http_client/pipeline_upload_client/pipeline_upload_service" + runParams "github.com/kubeflow/pipelines/backend/api/go_http_client/run_client/run_service" + "github.com/kubeflow/pipelines/backend/api/go_http_client/run_model" "github.com/kubeflow/pipelines/backend/src/common/client/api_server" "github.com/kubeflow/pipelines/backend/src/common/util" "github.com/kubeflow/pipelines/backend/test" @@ -17,8 +22,12 @@ import ( type ExperimentApiTest struct { suite.Suite - namespace string - experimentClient *api_server.ExperimentClient + namespace string + experimentClient *api_server.ExperimentClient + pipelineClient *api_server.PipelineClient + pipelineUploadClient *api_server.PipelineUploadClient + runClient *api_server.RunClient + jobClient *api_server.JobClient } // Check the namespace have ML job installed and ready @@ -41,6 +50,22 @@ func (s *ExperimentApiTest) SetupTest() { if err != nil { glog.Exitf("Failed to get experiment client. Error: %v", err) } + s.pipelineUploadClient, err = api_server.NewPipelineUploadClient(clientConfig, false) + if err != nil { + glog.Exitf("Failed to get pipeline upload client. Error: %s", err.Error()) + } + s.pipelineClient, err = api_server.NewPipelineClient(clientConfig, false) + if err != nil { + glog.Exitf("Failed to get pipeline client. Error: %s", err.Error()) + } + s.runClient, err = api_server.NewRunClient(clientConfig, false) + if err != nil { + glog.Exitf("Failed to get run client. Error: %s", err.Error()) + } + s.jobClient, err = api_server.NewJobClient(clientConfig, false) + if err != nil { + glog.Exitf("Failed to get job client. Error: %s", err.Error()) + } s.cleanUp() } @@ -62,7 +87,7 @@ func (s *ExperimentApiTest) TestExperimentAPI() { assert.Nil(t, err) expectedTrainingExperiment := &experiment_model.APIExperiment{ ID: trainingExperiment.ID, Name: experiment.Name, - Description: experiment.Description, CreatedAt: trainingExperiment.CreatedAt} + Description: experiment.Description, CreatedAt: trainingExperiment.CreatedAt, StorageState: "STORAGESTATE_AVAILABLE"} assert.Equal(t, expectedTrainingExperiment, trainingExperiment) /* ---------- Create an experiment with same name. Should fail due to name uniqueness ---------- */ @@ -159,6 +184,88 @@ func (s *ExperimentApiTest) TestExperimentAPI() { experiment, err = s.experimentClient.Get(¶ms.GetExperimentParams{ID: trainingExperiment.ID}) assert.Nil(t, err) assert.Equal(t, expectedTrainingExperiment, experiment) + + /* ---------- Create a pipeline version and two runs and two jobs -------------- */ + pipeline, err := s.pipelineUploadClient.UploadFile("../resources/hello-world.yaml", uploadParams.NewUploadPipelineParams()) + assert.Nil(t, err) + time.Sleep(1 * time.Second) + pipelineVersion, err := s.pipelineUploadClient.UploadPipelineVersion( + "../resources/hello-world.yaml", &uploadParams.UploadPipelineVersionParams{ + Name: util.StringPointer("hello-world-version"), + Pipelineid: util.StringPointer(pipeline.ID), + }) + assert.Nil(t, err) + createRunRequest := &runParams.CreateRunParams{Body: &run_model.APIRun{ + Name: "hello world", + Description: "this is hello world", + ResourceReferences: []*run_model.APIResourceReference{ + {Key: &run_model.APIResourceKey{Type: run_model.APIResourceTypeEXPERIMENT, ID: experiment.ID}, + Name: experiment.Name, Relationship: run_model.APIRelationshipOWNER}, + {Key: &run_model.APIResourceKey{Type: run_model.APIResourceTypePIPELINEVERSION, ID: pipelineVersion.ID}, + Relationship: run_model.APIRelationshipCREATOR}, + }, + }} + run1, _, err := s.runClient.Create(createRunRequest) + assert.Nil(t, err) + run2, _, err := s.runClient.Create(createRunRequest) + assert.Nil(t, err) + /* ---------- Create a new hello world job by specifying pipeline ID ---------- */ + createJobRequest := &jobParams.CreateJobParams{Body: &job_model.APIJob{ + Name: "hello world", + Description: "this is hello world", + ResourceReferences: []*job_model.APIResourceReference{ + {Key: &job_model.APIResourceKey{Type: job_model.APIResourceTypeEXPERIMENT, ID: experiment.ID}, + Relationship: job_model.APIRelationshipOWNER}, + {Key: &job_model.APIResourceKey{Type: job_model.APIResourceTypePIPELINEVERSION, ID: pipelineVersion.ID}, + Relationship: job_model.APIRelationshipCREATOR}, + }, + MaxConcurrency: 10, + Enabled: true, + }} + job1, err := s.jobClient.Create(createJobRequest) + assert.Nil(t, err) + job2, err := s.jobClient.Create(createJobRequest) + assert.Nil(t, err) + + /* ---------- Archive an experiment -----------------*/ + err = s.experimentClient.Archive(¶ms.ArchiveExperimentParams{ID: trainingExperiment.ID}) + + /* ---------- Verify experiment and its runs ------- */ + experiment, err = s.experimentClient.Get(¶ms.GetExperimentParams{ID: trainingExperiment.ID}) + assert.Nil(t, err) + assert.Equal(t, experiment_model.ExperimentStorageState("STORAGESTATE_ARCHIVED"), experiment.StorageState) + retrievedRun1, _, err := s.runClient.Get(&runParams.GetRunParams{RunID: run1.Run.ID}) + assert.Nil(t, err) + assert.Equal(t, run_model.RunStorageState("STORAGESTATE_ARCHIVED"), retrievedRun1.Run.StorageState) + retrievedRun2, _, err := s.runClient.Get(&runParams.GetRunParams{RunID: run2.Run.ID}) + assert.Nil(t, err) + assert.Equal(t, run_model.RunStorageState("STORAGESTATE_ARCHIVED"), retrievedRun2.Run.StorageState) + retrievedJob1, err := s.jobClient.Get(&jobParams.GetJobParams{ID: job1.ID}) + assert.Nil(t, err) + assert.Equal(t, false, retrievedJob1.Enabled) + retrievedJob2, err := s.jobClient.Get(&jobParams.GetJobParams{ID: job2.ID}) + assert.Nil(t, err) + assert.Equal(t, false, retrievedJob2.Enabled) + + /* ---------- Unarchive an experiment -----------------*/ + err = s.experimentClient.Unarchive(¶ms.UnarchiveExperimentParams{ID: trainingExperiment.ID}) + + /* ---------- Verify experiment and its runs and jobs --------- */ + experiment, err = s.experimentClient.Get(¶ms.GetExperimentParams{ID: trainingExperiment.ID}) + assert.Nil(t, err) + assert.Equal(t, experiment_model.ExperimentStorageState("STORAGESTATE_AVAILABLE"), experiment.StorageState) + retrievedRun1, _, err = s.runClient.Get(&runParams.GetRunParams{RunID: run1.Run.ID}) + assert.Nil(t, err) + assert.Equal(t, run_model.RunStorageState("STORAGESTATE_ARCHIVED"), retrievedRun1.Run.StorageState) + retrievedRun2, _, err = s.runClient.Get(&runParams.GetRunParams{RunID: run2.Run.ID}) + assert.Nil(t, err) + assert.Equal(t, run_model.RunStorageState("STORAGESTATE_ARCHIVED"), retrievedRun2.Run.StorageState) + retrievedJob1, err = s.jobClient.Get(&jobParams.GetJobParams{ID: job1.ID}) + assert.Nil(t, err) + assert.Equal(t, false, retrievedJob1.Enabled) + retrievedJob2, err = s.jobClient.Get(&jobParams.GetJobParams{ID: job2.ID}) + assert.Nil(t, err) + assert.Equal(t, false, retrievedJob2.Enabled) } func TestExperimentAPI(t *testing.T) { @@ -175,4 +282,7 @@ func (s *ExperimentApiTest) TearDownSuite() { func (s *ExperimentApiTest) cleanUp() { test.DeleteAllExperiments(s.experimentClient, s.T()) + test.DeleteAllPipelines(s.pipelineClient, s.T()) + test.DeleteAllRuns(s.runClient, s.T()) + test.DeleteAllJobs(s.jobClient, s.T()) } diff --git a/frontend/src/apis/experiment/api.ts b/frontend/src/apis/experiment/api.ts index 032e2bdf60f..8092c4b781f 100644 --- a/frontend/src/apis/experiment/api.ts +++ b/frontend/src/apis/experiment/api.ts @@ -117,6 +117,12 @@ export interface ApiExperiment { * @memberof ApiExperiment */ resource_references?: Array; + /** + * + * @type {ExperimentStorageState} + * @memberof ApiExperiment + */ + storage_state?: ExperimentStorageState; } /** @@ -242,6 +248,16 @@ export interface ApiStatus { details?: Array; } +/** + * + * @export + * @enum {string} + */ +export enum ExperimentStorageState { + AVAILABLE = 'STORAGESTATE_AVAILABLE', + ARCHIVED = 'STORAGESTATE_ARCHIVED', +} + /** * `Any` contains an arbitrary serialized protocol buffer message along with a URL that describes the type of the serialized message. Protobuf library provides support to pack/unpack Any values in the form of utility functions or additional generated methods of the Any type. Example 1: Pack and unpack a message in C++. Foo foo = ...; Any any; any.PackFrom(foo); ... if (any.UnpackTo(&foo)) { ... } Example 2: Pack and unpack a message in Java. Foo foo = ...; Any any = Any.pack(foo); ... if (any.is(Foo.class)) { foo = any.unpack(Foo.class); } Example 3: Pack and unpack a message in Python. foo = Foo(...) any = Any() any.Pack(foo) ... if any.Is(Foo.DESCRIPTOR): any.Unpack(foo) ... Example 4: Pack and unpack a message in Go foo := &pb.Foo{...} any, err := ptypes.MarshalAny(foo) ... foo := &pb.Foo{} if err := ptypes.UnmarshalAny(any, foo); err != nil { ... } The pack methods provided by protobuf library will by default use 'type.googleapis.com/full.type.name' as the type URL and the unpack methods only use the fully qualified type name after the last '/' in the type URL, for example \"foo.bar.com/x/y.z\" will yield type name \"y.z\". JSON ==== The JSON representation of an `Any` value uses the regular representation of the deserialized, embedded message, with an additional field `@type` which contains the type URL. Example: package google.profile; message Person { string first_name = 1; string last_name = 2; } { \"@type\": \"type.googleapis.com/google.profile.Person\", \"firstName\": , \"lastName\": } If the embedded message type is well-known and has a custom JSON representation, that representation will be embedded adding a field `value` which holds the custom JSON in addition to the `@type` field. Example (for message [google.protobuf.Duration][]): { \"@type\": \"type.googleapis.com/google.protobuf.Duration\", \"value\": \"1.212s\" } * @export @@ -268,6 +284,54 @@ export interface ProtobufAny { */ export const ExperimentServiceApiFetchParamCreator = function(configuration?: Configuration) { return { + /** + * + * @summary Archive an experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + archiveExperiment(id: string, options: any = {}): FetchArgs { + // verify required parameter 'id' is not null or undefined + if (id === null || id === undefined) { + throw new RequiredError( + 'id', + 'Required parameter id was null or undefined when calling archiveExperiment.', + ); + } + const localVarPath = `/apis/v1beta1/experiments/{id}:archive`.replace( + `{${'id'}}`, + encodeURIComponent(String(id)), + ); + const localVarUrlObj = url.parse(localVarPath, true); + const localVarRequestOptions = Object.assign({ method: 'POST' }, options); + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = + typeof configuration.apiKey === 'function' + ? configuration.apiKey('authorization') + : configuration.apiKey; + localVarHeaderParameter['authorization'] = localVarApiKeyValue; + } + + localVarUrlObj.query = Object.assign( + {}, + localVarUrlObj.query, + localVarQueryParameter, + options.query, + ); + // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 + delete localVarUrlObj.search; + localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + + return { + url: url.format(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @summary Create a new experiment. @@ -491,6 +555,54 @@ export const ExperimentServiceApiFetchParamCreator = function(configuration?: Co delete localVarUrlObj.search; localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + return { + url: url.format(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Restore an archived experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + unarchiveExperiment(id: string, options: any = {}): FetchArgs { + // verify required parameter 'id' is not null or undefined + if (id === null || id === undefined) { + throw new RequiredError( + 'id', + 'Required parameter id was null or undefined when calling unarchiveExperiment.', + ); + } + const localVarPath = `/apis/v1beta1/experiments/{id}:unarchive`.replace( + `{${'id'}}`, + encodeURIComponent(String(id)), + ); + const localVarUrlObj = url.parse(localVarPath, true); + const localVarRequestOptions = Object.assign({ method: 'POST' }, options); + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = + typeof configuration.apiKey === 'function' + ? configuration.apiKey('authorization') + : configuration.apiKey; + localVarHeaderParameter['authorization'] = localVarApiKeyValue; + } + + localVarUrlObj.query = Object.assign( + {}, + localVarUrlObj.query, + localVarQueryParameter, + options.query, + ); + // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 + delete localVarUrlObj.search; + localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + return { url: url.format(localVarUrlObj), options: localVarRequestOptions, @@ -505,6 +617,30 @@ export const ExperimentServiceApiFetchParamCreator = function(configuration?: Co */ export const ExperimentServiceApiFp = function(configuration?: Configuration) { return { + /** + * + * @summary Archive an experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + archiveExperiment( + id: string, + options?: any, + ): (fetch?: FetchAPI, basePath?: string) => Promise { + const localVarFetchArgs = ExperimentServiceApiFetchParamCreator( + configuration, + ).archiveExperiment(id, options); + return (fetch: FetchAPI = portableFetch, basePath: string = BASE_PATH) => { + return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then(response => { + if (response.status >= 200 && response.status < 300) { + return response.json(); + } else { + throw response; + } + }); + }; + }, /** * * @summary Create a new experiment. @@ -624,6 +760,30 @@ export const ExperimentServiceApiFp = function(configuration?: Configuration) { }); }; }, + /** + * + * @summary Restore an archived experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + unarchiveExperiment( + id: string, + options?: any, + ): (fetch?: FetchAPI, basePath?: string) => Promise { + const localVarFetchArgs = ExperimentServiceApiFetchParamCreator( + configuration, + ).unarchiveExperiment(id, options); + return (fetch: FetchAPI = portableFetch, basePath: string = BASE_PATH) => { + return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then(response => { + if (response.status >= 200 && response.status < 300) { + return response.json(); + } else { + throw response; + } + }); + }; + }, }; }; @@ -637,6 +797,16 @@ export const ExperimentServiceApiFactory = function( basePath?: string, ) { return { + /** + * + * @summary Archive an experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + archiveExperiment(id: string, options?: any) { + return ExperimentServiceApiFp(configuration).archiveExperiment(id, options)(fetch, basePath); + }, /** * * @summary Create a new experiment. @@ -704,6 +874,19 @@ export const ExperimentServiceApiFactory = function( options, )(fetch, basePath); }, + /** + * + * @summary Restore an archived experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + unarchiveExperiment(id: string, options?: any) { + return ExperimentServiceApiFp(configuration).unarchiveExperiment(id, options)( + fetch, + basePath, + ); + }, }; }; @@ -714,6 +897,21 @@ export const ExperimentServiceApiFactory = function( * @extends {BaseAPI} */ export class ExperimentServiceApi extends BaseAPI { + /** + * + * @summary Archive an experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ExperimentServiceApi + */ + public archiveExperiment(id: string, options?: any) { + return ExperimentServiceApiFp(this.configuration).archiveExperiment(id, options)( + this.fetch, + this.basePath, + ); + } + /** * * @summary Create a new experiment. @@ -797,4 +995,19 @@ export class ExperimentServiceApi extends BaseAPI { options, )(this.fetch, this.basePath); } + + /** + * + * @summary Restore an archived experiment. + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ExperimentServiceApi + */ + public unarchiveExperiment(id: string, options?: any) { + return ExperimentServiceApiFp(this.configuration).unarchiveExperiment(id, options)( + this.fetch, + this.basePath, + ); + } }