diff --git a/.github/workflows/deploy_external.yaml b/.github/workflows/deploy_external.yaml index 1702f0c27..cd8bca666 100644 --- a/.github/workflows/deploy_external.yaml +++ b/.github/workflows/deploy_external.yaml @@ -5,7 +5,7 @@ on: workflows: - 'product_builder' branches: - - 'develop' + - 'feat/release-candidate' types: - completed permissions: diff --git a/.github/workflows/product_builder.yaml b/.github/workflows/product_builder.yaml index 004630222..4c85893c1 100644 --- a/.github/workflows/product_builder.yaml +++ b/.github/workflows/product_builder.yaml @@ -69,9 +69,9 @@ jobs: crux: ${{ steps.filter.outputs.crux }} cruxui: ${{ steps.filter.outputs.cruxui }} kratos: ${{ steps.filter.outputs.kratos }} - tag: ${{ steps.settag.outputs.tag }} + tag: "0.15.0-rc" # ${{ steps.settag.outputs.tag }} extratag: ${{ steps.settag.outputs.extratag }} - version: ${{ steps.settag.outputs.version }} + version: "0.15.0-rc" # ${{ steps.settag.outputs.version }} minorversion: ${{ steps.settag.outputs.minorversion }} release: ${{ steps.release.outputs.release }} steps: @@ -669,11 +669,10 @@ jobs: defaults: run: working-directory: ${{ env.GOLANG_WORKING_DIRECTORY }} - needs: [gather_changes, e2e] + needs: [gather_changes, go_build] if: | always() && (github.ref_name == 'develop' || github.ref_name == 'main' || github.ref_type == 'tag') && - needs.e2e.result == 'success' && needs.go_build.result == 'success' && (needs.crux_build.result == 'success' || needs.crux_build.result == 'skipped') && (needs.crux-ui_build.result == 'success' || needs.crux-ui_build.result == 'skipped') && @@ -738,7 +737,6 @@ jobs: if: | always() && (github.ref_name == 'develop' || github.ref_name == 'main' || github.ref_type == 'tag') && - needs.e2e.result == 'success' && needs.go_build.result == 'success' && (needs.crux_build.result == 'success' || needs.crux_build.result == 'skipped') && (needs.crux-ui_build.result == 'success' || needs.crux-ui_build.result == 'skipped') && @@ -800,11 +798,10 @@ jobs: runs-on: ubuntu-22.04 container: image: ghcr.io/dyrector-io/dyrectorio/builder-images/signer:2 - needs: [crux_build, e2e, gather_changes] + needs: [crux_build, gather_changes] if: | always() && (github.ref_name == 'develop' || github.ref_name == 'main' || github.ref_type == 'tag') && - needs.e2e.result == 'success' && (needs.go_build.result == 'success' || needs.go_build.result == 'skipped') && needs.crux_build.result == 'success' && (needs.crux-ui_build.result == 'success' || needs.crux-ui_build.result == 'skipped') && @@ -863,11 +860,10 @@ jobs: runs-on: ubuntu-22.04 container: image: ghcr.io/dyrector-io/dyrectorio/builder-images/signer:2 - needs: [crux-ui_build, e2e, gather_changes] + needs: [crux-ui_build, gather_changes] if: | always() && (github.ref_name == 'develop' || github.ref_name == 'main' || github.ref_type == 'tag') && - needs.e2e.result == 'success' && (needs.go_build.result == 'success' || needs.go_build.result == 'skipped') && (needs.crux_build.result == 'success' || needs.crux_build.result == 'skipped') && needs.crux-ui_build.result == 'success' && @@ -926,11 +922,10 @@ jobs: runs-on: ubuntu-22.04 container: image: ghcr.io/dyrector-io/dyrectorio/builder-images/signer:2 - needs: [kratos_build, e2e, gather_changes] + needs: [kratos_build, gather_changes] if: | always() && (github.ref_name == 'develop' || github.ref_name == 'main' || github.ref_type == 'tag') && - needs.e2e.result == 'success' && (needs.go_build.result == 'success' || needs.go_build.result == 'skipped') && (needs.crux_build.result == 'success' || needs.crux_build.result == 'skipped') && (needs.crux-ui_build.result == 'success' || needs.crux-ui_build.result == 'skipped') && diff --git a/golang/internal/mapper/grpc_test.go b/golang/internal/mapper/grpc_test.go index c6531b5e8..08e8e57ae 100644 --- a/golang/internal/mapper/grpc_test.go +++ b/golang/internal/mapper/grpc_test.go @@ -67,17 +67,13 @@ func testExpectedCommon(req *agent.DeployWorkloadRequest) *v1.DeployImageRequest Password: "test-pass", }, InstanceConfig: v1.InstanceConfig{ - ContainerPreName: "test-prefix", - MountPath: "/path/to/mount", - Name: "test-prefix", - Environment: map[string]string{"Evn1": "Val1", "Env2": "Val2"}, - Registry: "", - RepositoryPreName: "repo-prefix", - SharedEnvironment: map[string]string{}, UseSharedEnvs: false, + Environment: map[string]string{}, + SharedEnvironment: map[string]string{}, + ContainerPreName: "", }, ContainerConfig: v1.ContainerConfig{ - ContainerPreName: "test-prefix", + ContainerPreName: "", Container: "test-common-config", Ports: []builder.PortBinding{{ExposedPort: 0x4d2, PortBinding: pointer.ToUint16(0x1a85)}}, PortRanges: []builder.PortRangeBinding{{Internal: builder.PortRange{From: 0x0, To: 0x18}, External: builder.PortRange{From: 0x40, To: 0x80}}}, @@ -153,7 +149,7 @@ func testExpectedCommon(req *agent.DeployWorkloadRequest) *v1.DeployImageRequest UseLoadBalancer: true, ExtraLBAnnotations: map[string]string{"annotation1": "value1"}, }, - RuntimeConfig: v1.Base64JSONBytes{0x6b, 0x65, 0x79, 0x31, 0x3d, 0x76, 0x61, 0x6c, 0x31, 0x2c, 0x6b, 0x65, 0x79, 0x32, 0x3d, 0x76, 0x61, 0x6c, 0x32}, // encoded string: a2V5MT12YWwxLGtleTI9dmFsMg== + RuntimeConfig: nil, Registry: req.Registry, ImageName: "test-image", Tag: "test-tag", @@ -212,22 +208,17 @@ func TestMapDockerContainerEventToContainerState(t *testing.T) { func testDeployRequest() *agent.DeployWorkloadRequest { registry := "https://my-registry.com" - runtimeCfg := "key1=val1,key2=val2" var uid int64 = 777 upLimit := "5Mi" - mntPath := "/path/to/mount" - repoPrefix := "repo-prefix" strategy := common.ExposeStrategy_EXPOSE_WITH_TLS b := true return &agent.DeployWorkloadRequest{ - Id: "testID", - ContainerName: "test-container", - ImageName: "test-image", - Tag: "test-tag", - Registry: ®istry, - RuntimeConfig: &runtimeCfg, - Dagent: testDagentConfig(), - Crane: testCraneConfig(), + Id: "testID", + ImageName: "test-image", + Tag: "test-tag", + Registry: ®istry, + Dagent: testDagentConfig(), + Crane: testCraneConfig(), Common: &agent.CommonContainerConfig{ Name: "test-common-config", Commands: []string{"make", "test"}, @@ -274,12 +265,6 @@ func testDeployRequest() *agent.DeployWorkloadRequest { Password: "test-pass", Url: "https://test-url.com", }, - InstanceConfig: &agent.InstanceConfig{ - Prefix: "test-prefix", - MountPath: &mntPath, - RepositoryPrefix: &repoPrefix, - Environment: map[string]string{"Evn1": "Val1", "Env2": "Val2"}, - }, } } diff --git a/golang/pkg/dagent/utils/docker.go b/golang/pkg/dagent/utils/docker.go index d4c7743fb..a52e1a89d 100644 --- a/golang/pkg/dagent/utils/docker.go +++ b/golang/pkg/dagent/utils/docker.go @@ -561,6 +561,11 @@ func getContainerPrefix(deployImageRequest *v1.DeployImageRequest) string { containerPrefix = deployImageRequest.InstanceConfig.ContainerPreName } } + + if containerPrefix == "" { + containerPrefix = deployImageRequest.ContainerConfig.ContainerPreName + } + return containerPrefix } diff --git a/protobuf/go/agent/agent.pb.go b/protobuf/go/agent/agent.pb.go index 819dd03c0..30837f2db 100644 --- a/protobuf/go/agent/agent.pb.go +++ b/protobuf/go/agent/agent.pb.go @@ -1865,16 +1865,15 @@ type DeployWorkloadRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ContainerName string `protobuf:"bytes,2,opt,name=containerName,proto3" json:"containerName,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // ContainerConfigs - Common *CommonContainerConfig `protobuf:"bytes,3,opt,name=common,proto3,oneof" json:"common,omitempty"` - Dagent *DagentContainerConfig `protobuf:"bytes,4,opt,name=dagent,proto3,oneof" json:"dagent,omitempty"` - Crane *CraneContainerConfig `protobuf:"bytes,5,opt,name=crane,proto3,oneof" json:"crane,omitempty"` - Registry *string `protobuf:"bytes,6,opt,name=registry,proto3,oneof" json:"registry,omitempty"` - ImageName string `protobuf:"bytes,7,opt,name=imageName,proto3" json:"imageName,omitempty"` - Tag string `protobuf:"bytes,8,opt,name=tag,proto3" json:"tag,omitempty"` - RegistryAuth *RegistryAuth `protobuf:"bytes,9,opt,name=registryAuth,proto3,oneof" json:"registryAuth,omitempty"` + Common *CommonContainerConfig `protobuf:"bytes,2,opt,name=common,proto3,oneof" json:"common,omitempty"` + Dagent *DagentContainerConfig `protobuf:"bytes,3,opt,name=dagent,proto3,oneof" json:"dagent,omitempty"` + Crane *CraneContainerConfig `protobuf:"bytes,4,opt,name=crane,proto3,oneof" json:"crane,omitempty"` + Registry *string `protobuf:"bytes,5,opt,name=registry,proto3,oneof" json:"registry,omitempty"` + ImageName string `protobuf:"bytes,6,opt,name=imageName,proto3" json:"imageName,omitempty"` + Tag string `protobuf:"bytes,7,opt,name=tag,proto3" json:"tag,omitempty"` + RegistryAuth *RegistryAuth `protobuf:"bytes,8,opt,name=registryAuth,proto3,oneof" json:"registryAuth,omitempty"` } func (x *DeployWorkloadRequest) Reset() { @@ -1916,13 +1915,6 @@ func (x *DeployWorkloadRequest) GetId() string { return "" } -func (x *DeployWorkloadRequest) GetContainerName() string { - if x != nil { - return x.ContainerName - } - return "" -} - func (x *DeployWorkloadRequest) GetCommon() *CommonContainerConfig { if x != nil { return x.Common @@ -2834,133 +2826,131 @@ var file_protobuf_proto_agent_proto_rawDesc = []byte{ 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x54, 0x54, 0x59, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, - 0x22, 0xc8, 0x03, 0x0a, 0x15, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x57, 0x6f, 0x72, 0x6b, 0x6c, + 0x22, 0xa2, 0x03, 0x0a, 0x15, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x39, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, - 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x06, 0x64, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x01, 0x52, 0x06, 0x64, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x05, 0x63, 0x72, 0x61, 0x6e, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x72, - 0x61, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x48, 0x02, 0x52, 0x05, 0x63, 0x72, 0x61, 0x6e, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1f, - 0x0a, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, - 0x1c, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, - 0x3c, 0x0a, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x48, 0x04, 0x52, 0x0c, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, - 0x07, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x64, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x63, 0x72, 0x61, 0x6e, 0x65, 0x42, 0x0b, 0x0a, - 0x09, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x22, 0x6a, 0x0a, 0x15, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x88, 0x01, - 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x6f, 0x6e, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x48, 0x01, 0x52, 0x07, 0x6f, 0x6e, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x88, 0x01, 0x01, - 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x0a, 0x0a, 0x08, 0x5f, - 0x6f, 0x6e, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x47, 0x0a, - 0x13, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4c, 0x65, - 0x67, 0x61, 0x63, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x12, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x26, - 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, - 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2b, 0x0a, 0x13, - 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x28, 0x0a, 0x10, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x22, 0x82, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x06, 0x64, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x48, 0x01, 0x52, 0x06, 0x64, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, + 0x12, 0x36, 0x0a, 0x05, 0x63, 0x72, 0x61, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x72, 0x61, 0x6e, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x02, 0x52, 0x05, + 0x63, 0x72, 0x61, 0x6e, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x3c, 0x0a, 0x0c, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x41, 0x75, 0x74, 0x68, 0x48, 0x04, 0x52, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x41, 0x75, 0x74, 0x68, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x64, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, + 0x06, 0x5f, 0x63, 0x72, 0x61, 0x6e, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x41, 0x75, 0x74, 0x68, 0x22, 0x6a, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, + 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x6f, + 0x6e, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x07, + 0x6f, 0x6e, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x70, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6f, 0x6e, 0x65, 0x53, 0x68, 0x6f, + 0x74, 0x22, 0x44, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, + 0x66, 0x69, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x47, 0x0a, 0x13, 0x44, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x12, 0x1c, + 0x0a, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, + 0x22, 0x64, 0x0a, 0x12, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x26, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2b, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x22, 0x28, 0x0a, 0x10, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x62, 0x6f, 0x72, + 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x82, 0x01, + 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x61, + 0x69, 0x6c, 0x22, 0x54, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, + 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, + 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x09, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x22, 0x44, 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x73, + 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, + 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0x69, + 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, + 0x18, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x43, + 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x45, 0x4c, 0x46, 0x5f, 0x44, + 0x45, 0x53, 0x54, 0x52, 0x55, 0x43, 0x54, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x48, 0x55, + 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x56, 0x4f, 0x4b, + 0x45, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x10, 0x04, 0x32, 0x9c, 0x05, 0x0a, 0x05, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x10, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x30, 0x01, 0x12, 0x37, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x12, 0x35, 0x0a, 0x0b, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x62, 0x6f, + 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2d, 0x0a, 0x0d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x12, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x10, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x44, 0x0a, 0x0e, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x54, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x22, 0x44, - 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0x69, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, - 0x53, 0x45, 0x4c, 0x46, 0x5f, 0x44, 0x45, 0x53, 0x54, 0x52, 0x55, 0x43, 0x54, 0x10, 0x02, 0x12, - 0x0c, 0x0a, 0x08, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x10, 0x0a, - 0x0c, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x10, 0x04, 0x32, - 0x9c, 0x05, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x07, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x12, 0x10, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x30, 0x01, 0x12, 0x37, 0x0a, - 0x0c, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x0b, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x0d, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2d, 0x0a, - 0x0d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x12, 0x0d, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x10, - 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x28, 0x01, 0x12, 0x44, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x42, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1b, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x4c, 0x6f, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x38, 0x0a, 0x0a, - 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x30, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, 0x10, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x12, 0x20, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, - 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x35, - 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x79, 0x72, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2d, 0x69, 0x6f, 0x2f, 0x64, 0x79, 0x72, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x6f, 0x2f, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x01, 0x12, 0x42, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, + 0x6f, 0x67, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x38, 0x0a, 0x0a, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x12, 0x30, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x73, 0x12, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x12, 0x3f, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, + 0x6f, 0x67, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x79, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2d, + 0x69, 0x6f, 0x2f, 0x64, 0x79, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x6f, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x6f, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/protobuf/proto/agent.proto b/protobuf/proto/agent.proto index 8b6e43eb4..57d949f53 100644 --- a/protobuf/proto/agent.proto +++ b/protobuf/proto/agent.proto @@ -231,18 +231,17 @@ message CommonContainerConfig { message DeployWorkloadRequest { string id = 1; - string containerName = 2; /* ContainerConfigs */ - optional CommonContainerConfig common = 3; - optional DagentContainerConfig dagent = 4; - optional CraneContainerConfig crane = 5; + optional CommonContainerConfig common = 2; + optional DagentContainerConfig dagent = 3; + optional CraneContainerConfig crane = 4; - optional string registry = 6; - string imageName = 7; - string tag = 8; + optional string registry = 5; + string imageName = 6; + string tag = 7; - optional RegistryAuth registryAuth = 9; + optional RegistryAuth registryAuth = 8; } message ContainerStateRequest { diff --git a/web/crux-ui/e2e/utils/config-bundle.ts b/web/crux-ui/e2e/utils/config-bundle.ts index 571fd2549..99b4f9851 100644 --- a/web/crux-ui/e2e/utils/config-bundle.ts +++ b/web/crux-ui/e2e/utils/config-bundle.ts @@ -31,7 +31,7 @@ export const createConfigBundle = async (page: Page, name: string, data: Record< const configId = page.url().split('/').pop() const ws = await sock - const wsRoute = TEAM_ROUTES.configBundle.detailsSocket(configId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(configId) await page.locator('button:has-text("Environment")').click() diff --git a/web/crux-ui/e2e/with-login/config-bundle.spec.ts b/web/crux-ui/e2e/with-login/config-bundle.spec.ts index 4c89a69c5..62751d66d 100644 --- a/web/crux-ui/e2e/with-login/config-bundle.spec.ts +++ b/web/crux-ui/e2e/with-login/config-bundle.spec.ts @@ -13,12 +13,14 @@ test('Creating a config bundle', async ({ page }) => { }) await page.goto(TEAM_ROUTES.configBundle.details(configBundleId)) + await page.waitForSelector(`h3:text-is("${BUNDLE_NAME}")`) + + await page.locator('button:has-text("Config")').click() + await page.waitForURL(TEAM_ROUTES.containerConfig.details('**')) const keyInput = page.locator('input[placeholder="Key"]').first() - await expect(keyInput).toBeDisabled() await expect(keyInput).toHaveValue(ENV_KEY) const valueInput = page.locator('input[placeholder="Value"]').first() - await expect(valueInput).toBeDisabled() await expect(valueInput).toHaveValue(ENV_VALUE) }) diff --git a/web/crux-ui/e2e/with-login/container-config/common-editor.spec.ts b/web/crux-ui/e2e/with-login/container-config/common-editor.spec.ts index 239b71fea..6fa73895e 100644 --- a/web/crux-ui/e2e/with-login/container-config/common-editor.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/common-editor.spec.ts @@ -1,5 +1,5 @@ +import { WS_TYPE_PATCH_CONFIG } from '@app/models' import { expect, Page } from '@playwright/test' -import { test } from '../../utils/test.fixture' import { NGINX_TEST_IMAGE_WITH_TAG, TEAM_ROUTES } from 'e2e/utils/common' import { createStorage } from 'e2e/utils/storages' import { @@ -20,37 +20,37 @@ import { wsPatchMatchVolume, } from 'e2e/utils/websocket-match' import { createImage, createProject, createVersion } from '../../utils/projects' +import { test } from '../../utils/test.fixture' import { waitSocketRef, wsPatchSent } from '../../utils/websocket' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { projectId, versionId, imageId } + return { imageConfigId } } test.describe.configure({ mode: 'parallel' }) test.describe('Image common config from editor', () => { test('Container name should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'name-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'name-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const name = 'new-container-name' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchContainerName(name)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchContainerName(name)) await page.locator('input[placeholder="Container name"]').fill(name) await wsSent @@ -60,15 +60,15 @@ test.describe('Image common config from editor', () => { }) test('Expose strategy should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'expose-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'expose-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchExpose('exposeWithTls')) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchExpose('exposeWithTls')) await page.getByRole('button', { name: 'HTTPS', exact: true }).click() await wsSent @@ -78,17 +78,17 @@ test.describe('Image common config from editor', () => { }) test('User should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'user-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'user-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const user = 23 - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchUser(user)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchUser(user)) await page.locator('input[placeholder="Container default"]').fill(user.toString()) await wsSent @@ -98,17 +98,17 @@ test.describe('Image common config from editor', () => { }) test('TTY should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'tty-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'tty-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("TTY")').click() - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchTTY(true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchTTY(true)) await page.locator('button[aria-checked="false"]:right-of(label:has-text("TTY"))').click() await wsSent @@ -118,13 +118,13 @@ test.describe('Image common config from editor', () => { }) test('Port should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'port-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'port-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Ports")').click() @@ -136,7 +136,7 @@ test.describe('Image common config from editor', () => { const internalInput = page.locator('input[placeholder="Internal"]') const externalInput = page.locator('input[placeholder="External"]') - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchPorts(internal, external)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchPorts(internal, external)) await internalInput.fill(internal) await externalInput.fill(external) await wsSent @@ -148,13 +148,13 @@ test.describe('Image common config from editor', () => { }) test('Port ranges should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'port-range-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'port-range-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Port ranges")').click() @@ -173,7 +173,7 @@ test.describe('Image common config from editor', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchPortRange(internalFrom, externalFrom, internalTo, externalTo), ) await internalInputFrom.fill(internalFrom) @@ -191,20 +191,20 @@ test.describe('Image common config from editor', () => { }) test('Secrets should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'secrets-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'secrets-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Secrets")').click() const secret = 'secretName' const secretInput = page.locator('input[placeholder="SECRETS"] >> visible=true').nth(0) - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchSecret(secret, true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchSecret(secret, true)) await secretInput.fill(secret) await page.getByRole('switch', { checked: false }).locator(':right-of(:text("Required"))').click() @@ -217,20 +217,20 @@ test.describe('Image common config from editor', () => { }) test('Commands should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'commands-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'commands-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Commands")').click() const command = 'sleep' const commandInput = page.locator('input[placeholder="Commands"] >> visible=true').nth(0) - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchCommand(command)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchCommand(command)) await commandInput.fill(command) await wsSent @@ -240,20 +240,20 @@ test.describe('Image common config from editor', () => { }) test('Arguments should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'arguments-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'arguments-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Arguments")').click() const argument = '1234' const argumentInput = page.locator('input[placeholder="Arguments"] >> visible=true').nth(0) - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchArgument(argument)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchArgument(argument)) await argumentInput.fill(argument) await wsSent @@ -263,12 +263,12 @@ test.describe('Image common config from editor', () => { }) test('Routing should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'routing-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'routing-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Ports")').click() @@ -278,7 +278,7 @@ test.describe('Image common config from editor', () => { const internalInput = page.locator('input[placeholder="Internal"]') - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchPorts(internal)) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchPorts(internal)) await internalInput.fill(internal) await wsSent @@ -293,7 +293,7 @@ test.describe('Image common config from editor', () => { wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchRouting(domain, path, uploadLimit, stripPath, routedPort), ) await page.locator('input[placeholder="Domain"]').fill(domain) @@ -314,24 +314,19 @@ test.describe('Image common config from editor', () => { }) test('Environment should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'environment-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'environment-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Environment")').click() const key = 'env-key' const value = 'env-value' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchEnvironment(key, value)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchEnvironment(key, value)) await page.locator('input[placeholder="Key"]').first().fill(key) await page.locator('input[placeholder="Value"]').first().fill(value) await wsSent @@ -343,17 +338,12 @@ test.describe('Image common config from editor', () => { }) test('Config container should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'config-container-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'config-container-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Config container")').click() const confDiv = page.locator('div.grid:has(label:has-text("CONFIG CONTAINER"))') @@ -362,7 +352,7 @@ test.describe('Image common config from editor', () => { const volume = 'volume' const path = 'test/path/' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchConfigContainer(img, volume, path, true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchConfigContainer(img, volume, path, true)) await confDiv.getByLabel('Image').fill(img) await confDiv.getByLabel('Volume').fill(volume) await confDiv.getByLabel('Path').fill(path) @@ -378,17 +368,12 @@ test.describe('Image common config from editor', () => { }) test('Init containers should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'init-container-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'init-container-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const name = 'container-name' const image = 'image' @@ -401,7 +386,7 @@ test.describe('Image common config from editor', () => { await page.locator('button:has-text("Init containers")').click() - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG) await page.locator(`[src="/plus.svg"]:right-of(label:has-text("Init containers"))`).first().click() await wsSent @@ -410,7 +395,7 @@ test.describe('Image common config from editor', () => { wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchInitContainer(name, image, volName, volPath, arg, cmd, envKey, envVal), ) await confDiv.getByLabel('NAME').fill(name) @@ -436,16 +421,16 @@ test.describe('Image common config from editor', () => { }) test('Volume should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'volume-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'volume-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Volume")').click() - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG) await page.locator(`[src="/plus.svg"]:right-of(label:has-text("Volume"))`).first().click() await wsSent @@ -454,7 +439,7 @@ test.describe('Image common config from editor', () => { const path = '/test/volume' const volumeClass = 'class' - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchVolume(name, size, path, volumeClass)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchVolume(name, size, path, volumeClass)) await page.getByLabel('Name').fill(name) await page.getByLabel('Size').fill(size) await page.getByLabel('Path').fill(path) @@ -470,20 +455,20 @@ test.describe('Image common config from editor', () => { }) test('Storage should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'storage-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'storage-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const storageName = 'image-editor-storage' const storageId = await createStorage(page, storageName, 'storage.com', '1234', '12345') const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Volume")').click() - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG) await page.locator(`[src="/plus.svg"]:right-of(label:has-text("Volume"))`).first().click() await wsSent @@ -492,7 +477,7 @@ test.describe('Image common config from editor', () => { const path = '/storage/volume' const volumeClass = 'class' - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchVolume(volumeName, size, path, volumeClass)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchVolume(volumeName, size, path, volumeClass)) await page.getByLabel('Name').fill(volumeName) await page.getByLabel('Size').fill(size) await page.getByLabel('Path').fill(path) @@ -503,7 +488,7 @@ test.describe('Image common config from editor', () => { const bucketPath = '/storage/' await page.locator('button:has-text("Storage")').click() - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchStorage(storageId, bucketPath, volumeName)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchStorage(storageId, bucketPath, volumeName)) await storageDiv.locator(`button:has-text("${storageName}")`).click() await storageDiv.locator('input[placeholder="Bucket path"]').fill(bucketPath) await storageDiv.locator(`button:has-text("${volumeName}")`).click() diff --git a/web/crux-ui/e2e/with-login/container-config/common-json.spec.ts b/web/crux-ui/e2e/with-login/container-config/common-json.spec.ts index a3a91d5f2..5432be017 100644 --- a/web/crux-ui/e2e/with-login/container-config/common-json.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/common-json.spec.ts @@ -21,32 +21,32 @@ import { } from 'e2e/utils/websocket-match' import { createImage, createProject, createVersion } from '../../utils/projects' import { waitSocketRef, wsPatchSent } from '../../utils/websocket' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' +import { WS_TYPE_PATCH_CONFIG } from '@app/models' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { projectId, versionId, imageId } + return { imageConfigId } } test.describe.configure({ mode: 'parallel' }) test.describe('Image common config from JSON', () => { test('Container name should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'name-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'name-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const name = 'new-container-name' @@ -57,7 +57,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.name = name - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchContainerName(name)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchContainerName(name)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -67,13 +67,13 @@ test.describe('Image common config from JSON', () => { }) test('Expose strategy should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'expose-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'expose-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -82,7 +82,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.expose = 'exposeWithTls' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchExpose('exposeWithTls')) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchExpose('exposeWithTls')) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -92,13 +92,13 @@ test.describe('Image common config from JSON', () => { }) test('User should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'user-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'user-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const user = 23 @@ -109,7 +109,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.user = user - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchUser(user)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchUser(user)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -119,13 +119,13 @@ test.describe('Image common config from JSON', () => { }) test('TTY should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'tty-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'tty-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -134,7 +134,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.tty = true - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchTTY(true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchTTY(true)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -144,13 +144,13 @@ test.describe('Image common config from JSON', () => { }) test('Port should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'port-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'port-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -164,7 +164,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.ports = [{ internal: internalAsNumber, external: externalAsNumber }] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchPorts(internal, external)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchPorts(internal, external)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -178,13 +178,13 @@ test.describe('Image common config from JSON', () => { }) test('Port ranges should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'port-range-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'port-range-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -210,7 +210,7 @@ test.describe('Image common config from JSON', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchPortRange(internalFrom, externalFrom, internalTo, externalTo), ) await jsonEditor.fill(JSON.stringify(json)) @@ -230,13 +230,13 @@ test.describe('Image common config from JSON', () => { }) test('Secrets should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'secrets-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'secrets-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const secret = 'secretName' const secretInput = page.locator('input[placeholder="SECRETS"] >> visible=true').nth(0) @@ -248,7 +248,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.secrets = [{ key: secret, required: true }] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchSecret(secret, true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchSecret(secret, true)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -259,13 +259,13 @@ test.describe('Image common config from JSON', () => { }) test('Commands should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'commands-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'commands-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const command = 'sleep' @@ -276,7 +276,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.commands = [command] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchCommand(command)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchCommand(command)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -286,13 +286,13 @@ test.describe('Image common config from JSON', () => { }) test('Arguments should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'arguments-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'arguments-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const argument = '1234' @@ -303,7 +303,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.args = [argument] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchArgument(argument)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchArgument(argument)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -313,12 +313,12 @@ test.describe('Image common config from JSON', () => { }) test('Routing should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'routing-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'routing-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -337,7 +337,7 @@ test.describe('Image common config from JSON', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchRouting(domain, path, uploadLimit, stripPath, port), ) await jsonEditor.fill(JSON.stringify(json)) @@ -352,12 +352,12 @@ test.describe('Image common config from JSON', () => { }) test('Environment should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'environment-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'environment-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const key = 'env-key' const value = 'env-value' @@ -369,7 +369,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.environment = { [key]: value } - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchEnvironment(key, value)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchEnvironment(key, value)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -380,17 +380,12 @@ test.describe('Image common config from JSON', () => { }) test('Config container should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'config-container-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'config-container-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const img = 'image' const volume = 'volume' @@ -403,7 +398,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.configContainer = { image: img, volume, path, keepFiles: true } - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchConfigContainer(img, volume, path, true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchConfigContainer(img, volume, path, true)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -417,17 +412,12 @@ test.describe('Image common config from JSON', () => { }) test('Init containers should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'init-container-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'init-container-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const name = 'container-name' const image = 'image' @@ -458,7 +448,7 @@ test.describe('Image common config from JSON', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchInitContainer(name, image, volName, volPath, arg, cmd, envKey, envVal), ) await jsonEditor.fill(JSON.stringify(json)) @@ -478,12 +468,12 @@ test.describe('Image common config from JSON', () => { }) test('Volume should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'volume-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'volume-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -497,7 +487,7 @@ test.describe('Image common config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.volumes = [{ name, path, type: 'rwo', class: volumeClass, size }] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchVolume(name, size, path, volumeClass)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchVolume(name, size, path, volumeClass)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -510,9 +500,9 @@ test.describe('Image common config from JSON', () => { }) test('Storage should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'storage-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + const { imageConfigId } = await setup(page, 'storage-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const volumeName = 'volume-name' const size = '1024' @@ -523,10 +513,10 @@ test.describe('Image common config from JSON', () => { const storageId = await createStorage(page, storageName, 'storage.com', '1234', '12345') const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) - await page.waitForSelector('h2:text-is("Image")') + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) + await page.waitForSelector('h2:text-is("Image config")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -536,7 +526,12 @@ test.describe('Image common config from JSON', () => { json.volumes = [{ name: volumeName, path, type: 'rwo', class: volumeClass, size }] json.storage = { storageId, bucket: bucketPath, path: volumeName } - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchStorage(storageId, bucketPath, volumeName)) + const wsSent = wsPatchSent( + ws, + wsRoute, + WS_TYPE_PATCH_CONFIG, + wsPatchMatchStorage(storageId, bucketPath, volumeName), + ) await jsonEditor.fill(JSON.stringify(json)) await wsSent diff --git a/web/crux-ui/e2e/with-login/container-config/container-config-filters.spec.ts b/web/crux-ui/e2e/with-login/container-config/container-config-filters.spec.ts index df1cae48d..fbf3249a5 100644 --- a/web/crux-ui/e2e/with-login/container-config/container-config-filters.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/container-config-filters.spec.ts @@ -1,30 +1,26 @@ import { expect, Page } from '@playwright/test' -import { test } from '../../utils/test.fixture' import { NGINX_TEST_IMAGE_WITH_TAG, TEAM_ROUTES } from 'e2e/utils/common' import { createImage, createProject, createVersion } from '../../utils/projects' +import { test } from '../../utils/test.fixture' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { - projectId, - versionId, - imageId, - } + return { imageConfigId } } test.describe('Filters', () => { test('None should be selected by default', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'filter-all', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'filter-all', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const allButton = await page.locator('button:has-text("All")') @@ -34,9 +30,9 @@ test.describe('Filters', () => { }) test('All should not be selected if one of the main filters are not selected', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'filter-select', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'filter-select', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') await page.locator(`button:has-text("Common")`).first().click() @@ -47,9 +43,9 @@ test.describe('Filters', () => { }) test('Main filter should not be selected if one of its sub filters are not selected', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'sub-filter', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'sub-filter', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const subFilter = await page.locator(`button:has-text("Network mode")`) @@ -62,9 +58,9 @@ test.describe('Filters', () => { }) test('Config field should be invisible if its sub filter is not selected', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'sub-deselect', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'sub-deselect', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const subFilter = await page.locator(`button:has-text("Deployment strategy")`) diff --git a/web/crux-ui/e2e/with-login/container-config/docker-editor.spec.ts b/web/crux-ui/e2e/with-login/container-config/docker-editor.spec.ts index 810c45490..7a68cc2e8 100644 --- a/web/crux-ui/e2e/with-login/container-config/docker-editor.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/docker-editor.spec.ts @@ -10,38 +10,33 @@ import { wsPatchMatchRestartPolicy, } from 'e2e/utils/websocket-match' import { createImage, createProject, createVersion } from '../../utils/projects' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' +import { WS_TYPE_PATCH_CONFIG } from '@app/models' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { projectId, versionId, imageId } + return { imageConfigId } } test.describe('Image docker config from editor', () => { test('Network mode should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'networkmode-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'networkmode-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const mode = 'host' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchNetworkMode(mode)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchNetworkMode(mode)) await page.locator(`div.grid:has(label:has-text("NETWORK MODE")) button:has-text("${mode}")`).click() await wsSent @@ -53,17 +48,12 @@ test.describe('Image docker config from editor', () => { }) test('Docker labels should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'dockerlabel-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'dockerlabel-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const key = 'docker-key' const value = 'docker-value' @@ -72,7 +62,7 @@ test.describe('Image docker config from editor', () => { await page.locator('button:has-text("Docker labels")').click() - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDockerLabel(key, value)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDockerLabel(key, value)) await keyInput.fill(key) await valueInput.fill(value) await wsSent @@ -84,19 +74,14 @@ test.describe('Image docker config from editor', () => { }) test('Restart policy should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'restartpolicy-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'restartpolicy-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchRestartPolicy('always')) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchRestartPolicy('always')) await page.locator('div.grid:has(label:has-text("RESTART POLICY")) button:has-text("Always")').click() await wsSent @@ -108,12 +93,12 @@ test.describe('Image docker config from editor', () => { }) test('Log config should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'logconfig-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'logconfig-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Log config")').click() @@ -123,7 +108,7 @@ test.describe('Image docker config from editor', () => { const loggerConf = page.locator('div.grid:has(label:has-text("LOG CONFIG"))') - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchLogConfig(type, key, value)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchLogConfig(type, key, value)) await loggerConf.locator('input[placeholder="Key"]').first().fill(key) await loggerConf.locator('input[placeholder="Value"]').first().fill(value) await loggerConf.locator(`button:has-text("${type}")`).click() @@ -137,18 +122,18 @@ test.describe('Image docker config from editor', () => { }) test('Networks should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'networks-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'networks-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Networks")').click() const network = '10.16.128.196' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchNetwork(network)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchNetwork(network)) await page.locator('div.grid:has(label:has-text("NETWORKS")) input[placeholder="Network"]').first().fill(network) await wsSent diff --git a/web/crux-ui/e2e/with-login/container-config/docker-json.spec.ts b/web/crux-ui/e2e/with-login/container-config/docker-json.spec.ts index 9ba93f576..ab69528e8 100644 --- a/web/crux-ui/e2e/with-login/container-config/docker-json.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/docker-json.spec.ts @@ -10,31 +10,31 @@ import { wsPatchMatchRestartPolicy, } from 'e2e/utils/websocket-match' import { createImage, createProject, createVersion } from '../../utils/projects' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' +import { WS_TYPE_PATCH_CONFIG } from '@app/models' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { projectId, versionId, imageId } + return { imageConfigId } } test.describe.configure({ mode: 'parallel' }) test.describe('Image docker config from JSON', () => { test('Network mode should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'networkmode-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'networkmode-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const mode = 'host' @@ -45,7 +45,7 @@ test.describe('Image docker config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.networkMode = mode - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchNetworkMode(mode)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchNetworkMode(mode)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -57,12 +57,12 @@ test.describe('Image docker config from JSON', () => { }) test('Docker labels should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'dockerlabel-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'dockerlabel-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const key = 'docker-key' const value = 'docker-value' @@ -74,7 +74,7 @@ test.describe('Image docker config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.dockerLabels = { [key]: value } - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDockerLabel(key, value)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDockerLabel(key, value)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -89,17 +89,12 @@ test.describe('Image docker config from JSON', () => { }) test('Restart policy should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'restartpolicy-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'restartpolicy-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -108,7 +103,7 @@ test.describe('Image docker config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.restartPolicy = 'always' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchRestartPolicy('always')) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchRestartPolicy('always')) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -120,12 +115,12 @@ test.describe('Image docker config from JSON', () => { }) test('Log config should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'logconfig-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'logconfig-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const type = 'json-file' const key = 'logger-key' @@ -138,7 +133,7 @@ test.describe('Image docker config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.logConfig = { driver: type, options: { [key]: value } } - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchLogConfig(type, key, value)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchLogConfig(type, key, value)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -151,12 +146,12 @@ test.describe('Image docker config from JSON', () => { }) test('Networks should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'networks-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'networks-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Networks")').click() @@ -169,7 +164,7 @@ test.describe('Image docker config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.networks = [network] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchNetwork(network)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchNetwork(network)) await jsonEditor.fill(JSON.stringify(json)) await wsSent diff --git a/web/crux-ui/e2e/with-login/container-config/image-config-view-state.spec.ts b/web/crux-ui/e2e/with-login/container-config/image-config-view-state.spec.ts index 1a9c3e35d..414acbf56 100644 --- a/web/crux-ui/e2e/with-login/container-config/image-config-view-state.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/image-config-view-state.spec.ts @@ -8,23 +8,19 @@ const setup = async ( projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { - projectId, - versionId, - imageId, - } + return { imageConfigId } } test.describe('View state', () => { test('Editor state should show the configuration fields', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'editor-state-conf', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'editor-state-conf', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const editorButton = await page.waitForSelector('button:has-text("Editor")') @@ -39,9 +35,9 @@ test.describe('View state', () => { }) test('JSON state should show the json editor', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'editor-state-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'editor-state-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') diff --git a/web/crux-ui/e2e/with-login/container-config/kubernetes-editor.spec.ts b/web/crux-ui/e2e/with-login/container-config/kubernetes-editor.spec.ts index 5a6cd1a3f..972d7a16f 100644 --- a/web/crux-ui/e2e/with-login/container-config/kubernetes-editor.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/kubernetes-editor.spec.ts @@ -18,39 +18,34 @@ import { } from 'e2e/utils/websocket-match' import { createImage, createProject, createVersion } from '../../utils/projects' import { waitSocketRef, wsPatchSent } from '../../utils/websocket' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' +import { WS_TYPE_PATCH_CONFIG } from '@app/models' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { projectId, versionId, imageId } + return { imageConfigId } } test.describe('Image kubernetes config from editor', () => { test('Deployment strategy should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'deployment-strategy-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'deployment-strategy-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const strategy = 'rolling' - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDeploymentStrategy(strategy)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDeploymentStrategy(strategy)) await page.locator(`button:has-text("${strategy}")`).click() await wsSent @@ -60,18 +55,13 @@ test.describe('Image kubernetes config from editor', () => { }) test('Custom headers should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'custom-headers-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'custom-headers-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Custom headers")').click() @@ -80,7 +70,7 @@ test.describe('Image kubernetes config from editor', () => { .locator('div.grid:has(label:has-text("CUSTOM HEADERS")) input[placeholder="Header name"]') .first() - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchCustomHeader(header)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchCustomHeader(header)) await input.fill(header) await wsSent @@ -90,22 +80,17 @@ test.describe('Image kubernetes config from editor', () => { }) test('Proxy headers should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'proxy-headers-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'proxy-headers-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Proxy headers")').click() - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchProxyHeader(true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchProxyHeader(true)) await page.locator('button[aria-checked="false"]:right-of(label:has-text("PROXY HEADERS"))').click() await wsSent @@ -115,29 +100,24 @@ test.describe('Image kubernetes config from editor', () => { }) test('Load balancer should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'load-balancer-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'load-balancer-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Use load balancer")').click() const key = 'balancer-key' const value = 'balancer-value' - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchLoadBalancer(true)) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchLoadBalancer(true)) await page.locator('button[aria-checked="false"]:right-of(label:has-text("USE LOAD BALANCER"))').click() await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchLBAnnotations(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchLBAnnotations(key, value)) await page.locator('div.grid:has(label:has-text("USE LOAD BALANCER")) input[placeholder="Key"]').first().fill(key) await page .locator('div.grid:has(label:has-text("USE LOAD BALANCER")) input[placeholder="Value"]') @@ -159,18 +139,13 @@ test.describe('Image kubernetes config from editor', () => { }) test('Health check config should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'health-check-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'health-check-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Health check config")').click() @@ -184,7 +159,7 @@ test.describe('Image kubernetes config from editor', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchHealthCheck(port, liveness, readiness, startup), ) await hcConf.locator('input[placeholder="Port"]').fill(port.toString()) @@ -202,17 +177,12 @@ test.describe('Image kubernetes config from editor', () => { }) test('Resource config should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'resource-config-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'resource-config-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Resource config")').click() @@ -226,7 +196,7 @@ test.describe('Image kubernetes config from editor', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchResourceConfig(cpuLimits, cpuRequests, memoryLimits, memoryRequests), ) await rsConf.locator('input').nth(0).fill(cpuLimits) @@ -247,13 +217,13 @@ test.describe('Image kubernetes config from editor', () => { page.locator(`div.max-h-128 > div:nth-child(2):near(label:has-text("${category}"))`) test('Labels should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'labels-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'labels-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.getByRole('button', { name: 'Labels', exact: true }).click() @@ -264,15 +234,15 @@ test.describe('Image kubernetes config from editor', () => { const serviceDiv = await getCategoryDiv('Service', page) const ingressDiv = await getCategoryDiv('Ingress', page) - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDeploymentLabel(key, value)) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDeploymentLabel(key, value)) await deploymentDiv.locator('input[placeholder="Key"]').first().fill(key) await deploymentDiv.locator('input[placeholder="Value"]').first().fill(value) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchServiceLabel(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchServiceLabel(key, value)) await serviceDiv.locator('input[placeholder="Key"]').first().fill(key) await serviceDiv.locator('input[placeholder="Value"]').first().fill(value) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchIngressLabel(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchIngressLabel(key, value)) await ingressDiv.locator('input[placeholder="Key"]').first().fill(key) await ingressDiv.locator('input[placeholder="Value"]').first().fill(value) await wsSent @@ -288,18 +258,13 @@ test.describe('Image kubernetes config from editor', () => { }) test('Annotations should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'annotations-editor', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'annotations-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.getByRole('button', { name: 'Annotations', exact: true }).click() @@ -310,15 +275,15 @@ test.describe('Image kubernetes config from editor', () => { const serviceDiv = await getCategoryDiv('Service', page) const ingressDiv = await getCategoryDiv('Ingress', page) - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDeploymentAnnotations(key, value)) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDeploymentAnnotations(key, value)) await deploymentDiv.locator('input[placeholder="Key"]').first().fill(key) await deploymentDiv.locator('input[placeholder="Value"]').first().fill(value) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchServiceAnnotations(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchServiceAnnotations(key, value)) await serviceDiv.locator('input[placeholder="Key"]').first().fill(key) await serviceDiv.locator('input[placeholder="Value"]').first().fill(value) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchIngressAnnotations(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchIngressAnnotations(key, value)) await ingressDiv.locator('input[placeholder="Key"]').first().fill(key) await ingressDiv.locator('input[placeholder="Value"]').first().fill(value) await wsSent diff --git a/web/crux-ui/e2e/with-login/container-config/kubernetes-json.spec.ts b/web/crux-ui/e2e/with-login/container-config/kubernetes-json.spec.ts index 9fa54071a..3e372bf41 100644 --- a/web/crux-ui/e2e/with-login/container-config/kubernetes-json.spec.ts +++ b/web/crux-ui/e2e/with-login/container-config/kubernetes-json.spec.ts @@ -1,5 +1,5 @@ +import { WS_TYPE_PATCH_CONFIG } from '@app/models' import { expect, Page } from '@playwright/test' -import { test } from '../../utils/test.fixture' import { NGINX_TEST_IMAGE_WITH_TAG, TEAM_ROUTES } from 'e2e/utils/common' import { wsPatchMatchCustomHeader, @@ -17,36 +17,31 @@ import { wsPatchMatchServiceLabel, } from 'e2e/utils/websocket-match' import { createImage, createProject, createVersion } from '../../utils/projects' +import { test } from '../../utils/test.fixture' import { waitSocketRef, wsPatchSent } from '../../utils/websocket' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) - return { projectId, versionId, imageId } + return { imageConfigId } } test.describe('Image kubernetes config from JSON', () => { test('Deployment strategy should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'deployment-strategy-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'deployment-strategy-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const strategy = 'rolling' @@ -57,7 +52,7 @@ test.describe('Image kubernetes config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.deploymentStrategy = strategy - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDeploymentStrategy(strategy)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDeploymentStrategy(strategy)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -67,18 +62,13 @@ test.describe('Image kubernetes config from JSON', () => { }) test('Custom headers should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'custom-headers-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'custom-headers-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const header = 'test-header' @@ -89,7 +79,7 @@ test.describe('Image kubernetes config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.customHeaders = [header] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchCustomHeader(header)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchCustomHeader(header)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -102,18 +92,13 @@ test.describe('Image kubernetes config from JSON', () => { }) test('Proxy headers should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'proxy-headers-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'proxy-headers-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -122,7 +107,7 @@ test.describe('Image kubernetes config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.proxyHeaders = true - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchProxyHeader(true)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchProxyHeader(true)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -132,18 +117,13 @@ test.describe('Image kubernetes config from JSON', () => { }) test('Load balancer should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'load-balancer-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'load-balancer-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const key = 'balancer-key' const value = 'balancer-value' @@ -155,11 +135,11 @@ test.describe('Image kubernetes config from JSON', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.useLoadBalancer = true - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchLoadBalancer(true)) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchLoadBalancer(true)) await jsonEditor.fill(JSON.stringify(json)) await wsSent json.extraLBAnnotations = { [key]: value } - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchLBAnnotations(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchLBAnnotations(key, value)) await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -177,13 +157,13 @@ test.describe('Image kubernetes config from JSON', () => { }) test('Health check config should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'health-check-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'health-check-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const port = 12560 const liveness = 'test/liveness/' @@ -200,7 +180,7 @@ test.describe('Image kubernetes config from JSON', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchHealthCheck(port, liveness, readiness, startup), ) await jsonEditor.fill(JSON.stringify(json)) @@ -216,18 +196,13 @@ test.describe('Image kubernetes config from JSON', () => { }) test('Resource config should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup( - page, - 'resource-config-json', - '1.0.0', - NGINX_TEST_IMAGE_WITH_TAG, - ) + const { imageConfigId } = await setup(page, 'resource-config-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const cpuLimits = '50' const cpuRequests = '25' @@ -247,7 +222,7 @@ test.describe('Image kubernetes config from JSON', () => { const wsSent = wsPatchSent( ws, wsRoute, - WS_TYPE_PATCH_IMAGE, + WS_TYPE_PATCH_CONFIG, wsPatchMatchResourceConfig(cpuLimits, cpuRequests, memoryLimits, memoryRequests), ) await jsonEditor.fill(JSON.stringify(json)) @@ -266,13 +241,13 @@ test.describe('Image kubernetes config from JSON', () => { page.locator(`div.max-h-128 > div:nth-child(2):near(label:has-text("${category}"))`) test('Labels should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'labels-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'labels-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const key = 'label-key' const value = 'label-value' @@ -283,15 +258,15 @@ test.describe('Image kubernetes config from JSON', () => { const jsonEditor = await page.locator('textarea') const json = JSON.parse(await jsonEditor.inputValue()) - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDeploymentLabel(key, value)) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDeploymentLabel(key, value)) json.labels = { deployment: { [key]: value } } await jsonEditor.fill(JSON.stringify(json)) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchServiceLabel(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchServiceLabel(key, value)) json.labels = { deployment: { [key]: value }, service: { [key]: value } } await jsonEditor.fill(JSON.stringify(json)) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchIngressLabel(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchIngressLabel(key, value)) json.labels = { deployment: { [key]: value }, service: { [key]: value }, ingress: { [key]: value } } await jsonEditor.fill(JSON.stringify(json)) await wsSent @@ -310,13 +285,13 @@ test.describe('Image kubernetes config from JSON', () => { }) test('Annotations should be saved', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'annotations-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'annotations-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const key = 'annotation-key' const value = 'annotation-value' @@ -327,15 +302,15 @@ test.describe('Image kubernetes config from JSON', () => { const jsonEditor = await page.locator('textarea') const json = JSON.parse(await jsonEditor.inputValue()) - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchDeploymentAnnotations(key, value)) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchDeploymentAnnotations(key, value)) json.annotations = { deployment: { [key]: value } } await jsonEditor.fill(JSON.stringify(json)) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchServiceAnnotations(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchServiceAnnotations(key, value)) json.annotations = { deployment: { [key]: value }, service: { [key]: value } } await jsonEditor.fill(JSON.stringify(json)) await wsSent - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchIngressAnnotations(key, value)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchIngressAnnotations(key, value)) json.annotations = { deployment: { [key]: value }, service: { [key]: value }, ingress: { [key]: value } } await jsonEditor.fill(JSON.stringify(json)) await wsSent diff --git a/web/crux-ui/e2e/with-login/deployment/deployment-copy.spec.ts b/web/crux-ui/e2e/with-login/deployment/deployment-copy.spec.ts index 72b356a47..99bd90b95 100644 --- a/web/crux-ui/e2e/with-login/deployment/deployment-copy.spec.ts +++ b/web/crux-ui/e2e/with-login/deployment/deployment-copy.spec.ts @@ -1,4 +1,4 @@ -import { WS_TYPE_PATCH_IMAGE, WS_TYPE_PATCH_INSTANCE } from '@app/models' +import { WS_TYPE_PATCH_CONFIG, WS_TYPE_PATCH_INSTANCE } from '@app/models' import { Page, expect } from '@playwright/test' import { wsPatchMatchEverySecret, wsPatchMatchNonNullSecretValues } from 'e2e/utils/websocket-match' import { DAGENT_NODE, NGINX_TEST_IMAGE_WITH_TAG, TEAM_ROUTES, waitForURLExcept } from '../../utils/common' @@ -21,10 +21,10 @@ const addSecretToImage = async ( secretKeys: string[], ): Promise => { const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -33,7 +33,7 @@ const addSecretToImage = async ( const json = JSON.parse(await jsonEditor.inputValue()) json.secrets = secretKeys.map(key => ({ key, required: false })) - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchEverySecret(secretKeys)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchEverySecret(secretKeys)) await jsonEditor.fill(JSON.stringify(json)) await wsSent } @@ -73,9 +73,9 @@ test.describe('Deployment Copy', () => { await createNode(page, newNodeName) const versionId = await createVersion(page, projectId, '0.1.0', 'Incremental') - const imageId = await createImage(page, projectId, versionId, NGINX_TEST_IMAGE_WITH_TAG) + const imageConfigId = await createImage(page, projectId, versionId, NGINX_TEST_IMAGE_WITH_TAG) - await addSecretToImage(page, projectId, versionId, imageId, secretKeys) + await addSecretToImage(page, projectId, versionId, imageConfigId, secretKeys) const { id: deploymentId } = await addDeploymentToVersion(page, projectId, versionId, DAGENT_NODE, { prefix: originalPrefix, diff --git a/web/crux-ui/e2e/with-login/deployment/deployment-copyability-versioned.spec.ts b/web/crux-ui/e2e/with-login/deployment/deployment-copyability-versioned.spec.ts index 39b799f2d..5837f5cb0 100644 --- a/web/crux-ui/e2e/with-login/deployment/deployment-copyability-versioned.spec.ts +++ b/web/crux-ui/e2e/with-login/deployment/deployment-copyability-versioned.spec.ts @@ -124,7 +124,7 @@ test.describe('Versioned Project', () => { await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const editorButton = await page.waitForSelector('button:has-text("JSON")') await editorButton.click() diff --git a/web/crux-ui/e2e/with-login/deployment/deployment-deletability.spec.ts b/web/crux-ui/e2e/with-login/deployment/deployment-deletability.spec.ts index 818ac7305..7d605877c 100644 --- a/web/crux-ui/e2e/with-login/deployment/deployment-deletability.spec.ts +++ b/web/crux-ui/e2e/with-login/deployment/deployment-deletability.spec.ts @@ -4,20 +4,20 @@ import { NGINX_TEST_IMAGE_WITH_TAG, TEAM_ROUTES } from 'e2e/utils/common' import { deployWithDagent } from '../../utils/node-helper' import { addImageToVersion, createImage, createProject, createVersion } from '../../utils/projects' import { waitSocketRef, wsPatchSent } from '../../utils/websocket' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' +import { WS_TYPE_PATCH_CONFIG } from '@app/models' test('In progress deployment should be not deletable', async ({ page }) => { const projectName = 'project-delete-test-1' const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, '0.1.0', 'Incremental') - const imageId = await createImage(page, projectId, versionId, 'nginx') + const imageConfigId = await createImage(page, projectId, versionId, 'nginx') const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const editorButton = await page.waitForSelector('button:has-text("JSON")') await editorButton.click() @@ -38,7 +38,7 @@ test('In progress deployment should be not deletable', async ({ page }) => { useParentConfig: false, }, ] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG) await jsonContainer.fill(JSON.stringify(configObject)) await wsSent diff --git a/web/crux-ui/e2e/with-login/image-config.spec.ts b/web/crux-ui/e2e/with-login/image-config.spec.ts index 88d17dcd2..eb009625d 100644 --- a/web/crux-ui/e2e/with-login/image-config.spec.ts +++ b/web/crux-ui/e2e/with-login/image-config.spec.ts @@ -1,32 +1,32 @@ +import { WS_TYPE_PATCH_CONFIG } from '@app/models' import { expect, Page } from '@playwright/test' -import { test } from '../utils/test.fixture' import { NGINX_TEST_IMAGE_WITH_TAG, screenshotPath, TEAM_ROUTES } from '../utils/common' import { createImage, createProject, createVersion } from '../utils/projects' +import { test } from '../utils/test.fixture' import { waitSocketRef, wsPatchSent } from '../utils/websocket' -import { WS_TYPE_PATCH_IMAGE } from '@app/models' const setup = async ( page: Page, projectName: string, versionName: string, imageName: string, -): Promise<{ projectId: string; versionId: string; imageId: string }> => { +): Promise<{ projectId: string; versionId: string; imageConfigId: string }> => { const projectId = await createProject(page, projectName, 'versioned') const versionId = await createVersion(page, projectId, versionName, 'Incremental') - const imageId = await createImage(page, projectId, versionId, imageName) + const imageConfigId = await createImage(page, projectId, versionId, imageName) return { projectId, versionId, - imageId, + imageConfigId, } } test.describe('View state', () => { test('Editor state should show the configuration fields', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'editor-state-conf', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'editor-state-conf', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const editorButton = await page.waitForSelector('button:has-text("Editor")') @@ -40,9 +40,9 @@ test.describe('View state', () => { }) test('JSON state should show the json editor', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'editor-state-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'editor-state-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') @@ -57,9 +57,9 @@ test.describe('View state', () => { test.describe('Filters', () => { test('None should be selected by default', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'filter-all', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'filter-all', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const allButton = await page.locator('button:has-text("All")') @@ -69,9 +69,9 @@ test.describe('Filters', () => { }) test('All should not be selected if one of the main filters are not selected', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'filter-select', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'filter-select', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') await page.locator(`button:has-text("Common")`).first().click() @@ -82,9 +82,9 @@ test.describe('Filters', () => { }) test('Main filter should not be selected if one of its sub filters are not selected', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'sub-filter', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'sub-filter', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const subFilter = await page.locator(`button:has-text("Network mode")`) @@ -96,9 +96,9 @@ test.describe('Filters', () => { }) test('Config field should be invisible if its sub filter is not selected', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'sub-deselect', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'sub-deselect', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const subFilter = await page.locator(`button:has-text("Deployment strategy")`) @@ -119,17 +119,17 @@ const wsPatchMatchPorts = (internalPort: string, externalPort?: string) => (payl test.describe('Image configurations', () => { test('Port should be saved after adding it from the config field', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'port-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'port-editor', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) await page.locator('button:has-text("Ports")').click() - let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE) + let wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG) const addPortsButton = await page.locator(`[src="/plus.svg"]:right-of(label:has-text("Ports"))`).first() await addPortsButton.click() await wsSent @@ -140,7 +140,7 @@ test.describe('Image configurations', () => { const internalInput = page.locator('input[placeholder="Internal"]') const externalInput = page.locator('input[placeholder="External"]') - wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchPorts(internal, external)) + wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchPorts(internal, external)) await internalInput.type(internal) await externalInput.type(external) await wsSent @@ -152,13 +152,13 @@ test.describe('Image configurations', () => { }) test('Port should be saved after adding it from the json editor', async ({ page }) => { - const { projectId, versionId, imageId } = await setup(page, 'port-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) + const { imageConfigId } = await setup(page, 'port-json', '1.0.0', NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(versionId, imageId)) + await page.goto(TEAM_ROUTES.containerConfig.details(imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock - const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(versionId) + const wsRoute = TEAM_ROUTES.containerConfig.detailsSocket(imageConfigId) const jsonEditorButton = await page.waitForSelector('button:has-text("JSON")') await jsonEditorButton.click() @@ -172,7 +172,7 @@ test.describe('Image configurations', () => { const json = JSON.parse(await jsonEditor.inputValue()) json.ports = [{ internal: internalAsNumber, external: externalAsNumber }] - const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_IMAGE, wsPatchMatchPorts(internal, external)) + const wsSent = wsPatchSent(ws, wsRoute, WS_TYPE_PATCH_CONFIG, wsPatchMatchPorts(internal, external)) await jsonEditor.fill(JSON.stringify(json)) await wsSent diff --git a/web/crux-ui/e2e/with-login/resource-copy.spec.ts b/web/crux-ui/e2e/with-login/resource-copy.spec.ts index 86dd95955..947ec6be4 100644 --- a/web/crux-ui/e2e/with-login/resource-copy.spec.ts +++ b/web/crux-ui/e2e/with-login/resource-copy.spec.ts @@ -1,4 +1,4 @@ -import { WS_TYPE_PATCH_IMAGE, WS_TYPE_PATCH_INSTANCE } from '@app/models' +import { WS_TYPE_PATCH_CONFIG, WS_TYPE_PATCH_INSTANCE } from '@app/models' import { expect } from '@playwright/test' import { DAGENT_NODE, NGINX_TEST_IMAGE_WITH_TAG, TEAM_ROUTES, waitForURLExcept } from 'e2e/utils/common' import { addPortsToContainerConfig } from 'e2e/utils/container-config' @@ -51,17 +51,17 @@ test.describe('Deleting default version', () => { const projectId = await createProject(page, projectName, 'versioned') const defaultVersionName = 'default-version' const defaultVersionId = await createVersion(page, projectId, defaultVersionName, 'Rolling') - const defaultVersionImageId = await createImage(page, projectId, defaultVersionId, NGINX_TEST_IMAGE_WITH_TAG) + const imageConfigId = await createImage(page, projectId, defaultVersionId, NGINX_TEST_IMAGE_WITH_TAG) const sock = waitSocketRef(page) - await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(defaultVersionId, defaultVersionImageId)) + await page.goto(TEAM_ROUTES.project.versions(projectId).imageDetails(defaultVersionId, imageConfigId)) await page.waitForSelector('h2:text-is("Image")') const ws = await sock const wsRoute = TEAM_ROUTES.project.versions(projectId).detailsSocket(defaultVersionId) const internal = '1000' const external = '2000' - await addPortsToContainerConfig(page, ws, wsRoute, WS_TYPE_PATCH_IMAGE, internal, external) + await addPortsToContainerConfig(page, ws, wsRoute, WS_TYPE_PATCH_CONFIG, internal, external) const newVersionId = await createVersion(page, projectId, 'new-version', 'Rolling') diff --git a/web/crux-ui/package.json b/web/crux-ui/package.json index 2ae23b454..83f8ca63d 100644 --- a/web/crux-ui/package.json +++ b/web/crux-ui/package.json @@ -1,6 +1,6 @@ { "name": "crux-ui", - "version": "0.14.1", + "version": "0.15.0-rc", "description": "Open-source delivery platform that helps developers to deliver applications efficiently by simplifying software releases and operations in any environment.", "author": "dyrector.io", "private": true, diff --git a/web/crux-ui/src/components/container-configs/edit-container-config-card.tsx b/web/crux-ui/src/components/container-configs/edit-container-config-card.tsx index f5964ebe3..3564fde5e 100644 --- a/web/crux-ui/src/components/container-configs/edit-container-config-card.tsx +++ b/web/crux-ui/src/components/container-configs/edit-container-config-card.tsx @@ -10,7 +10,7 @@ import DyoMessage from '@app/elements/dyo-message' import { DyoConfirmationModal } from '@app/elements/dyo-modal' import useConfirmation from '@app/hooks/use-confirmation' import { ContainerConfig, ContainerConfigParent, VersionImage } from '@app/models' -import { createConfigSchema, getValidationError } from '@app/validations' +import { createContainerConfigSchema, getValidationError } from '@app/validations' import useTranslation from 'next-translate/useTranslation' import { QA_DIALOG_LABEL_DELETE_IMAGE } from 'quality-assurance' import ContainerConfigJsonEditor from './container-config-json-editor' @@ -74,7 +74,7 @@ const EditContainerConfigCard = (props: Ed const errorMessage = state.parseError ?? - getValidationError(createConfigSchema('image', image?.labels ?? {}), state.config, null, t)?.message + getValidationError(createContainerConfigSchema(image?.labels ?? {}), state.config, null, t)?.message return ( <> diff --git a/web/crux-ui/src/models/image.ts b/web/crux-ui/src/models/image.ts index e1a9abc65..6d9c89ed3 100644 --- a/web/crux-ui/src/models/image.ts +++ b/web/crux-ui/src/models/image.ts @@ -79,4 +79,13 @@ export type ImageMessage = VersionImage export const imageNameOf = (image: VersionImage): string => imageName(image.name, image.tag) -export const containerNameOfImage = (image: VersionImage) => image.config.name ?? image.name +export const registryImageNameToContainerName = (name: string) => { + if (name.includes('/')) { + return name.split('/').pop() + } + + return name +} + +export const containerNameOfImage = (image: VersionImage) => + image.config.name ?? registryImageNameToContainerName(image.name) diff --git a/web/crux-ui/src/pages/[teamSlug]/container-configurations/[configId].tsx b/web/crux-ui/src/pages/[teamSlug]/container-configurations/[configId].tsx index 21b92ad4f..ac1fad5f2 100644 --- a/web/crux-ui/src/pages/[teamSlug]/container-configurations/[configId].tsx +++ b/web/crux-ui/src/pages/[teamSlug]/container-configurations/[configId].tsx @@ -50,8 +50,8 @@ import { TeamRoutes } from '@app/routes' import { withContextAuthorization } from '@app/utils' import { ContainerConfigValidationErrors, - createConfigSchema, - getConfigFieldErrorsForSchema, + getConcreteContainerConfigFieldErrors, + getContainerConfigFieldErrors, jsonErrorOf, } from '@app/validations' import { WsMessage } from '@app/websockets/common' @@ -134,8 +134,15 @@ const getConfigErrors = ( config: ContainerConfigDetails, imageLabels: Record, t: Translate, -): ContainerConfigValidationErrors => - getConfigFieldErrorsForSchema(createConfigSchema(config.type, imageLabels), config, t) +): ContainerConfigValidationErrors => { + const type = containerConfigTypeToSectionType(config.type) + + if (type === 'concrete') { + return getConcreteContainerConfigFieldErrors(config as ConcreteContainerConfigData, imageLabels, t) + } + + return getContainerConfigFieldErrors(config, imageLabels, t) +} const getBaseConfig = (config: ContainerConfigDetails, relations: ContainerConfigRelations): ContainerConfigData => { switch (config.type) { diff --git a/web/crux-ui/src/routes.ts b/web/crux-ui/src/routes.ts index 99b505fc3..61f2e8a0f 100644 --- a/web/crux-ui/src/routes.ts +++ b/web/crux-ui/src/routes.ts @@ -699,8 +699,6 @@ class ConfigBundleRoutes { list = (options?: ListRouteOptions) => appendAnchorWhenDeclared(this.root, ANCHOR_NEW, options?.new) details = (id: string) => `${this.root}/${id}` - - detailsSocket = (id: string) => this.details(id) } export class PackageApi { diff --git a/web/crux-ui/src/validations/container.ts b/web/crux-ui/src/validations/container.ts index 0f27e981e..79a25f6f0 100644 --- a/web/crux-ui/src/validations/container.ts +++ b/web/crux-ui/src/validations/container.ts @@ -18,7 +18,6 @@ import { Metrics, UniqueKeyValue, VolumeType, - ContainerConfigType, } from '@app/models' import * as yup from 'yup' import { matchNoLeadingOrTrailingWhitespaces, matchNoWhitespace } from './common' @@ -503,39 +502,29 @@ const testRules = (rules: [string, EnvironmentRule][], arr: UniqueKeyValue[], fi return null } -const createContainerConfigBaseSchema = ( - imageLabels: Record, - nameRequired: boolean, - secretsHaveValue: boolean, -) => - yup - .object() - .shape({ - name: matchContainerName( - nameRequired - ? yup.string().required().label('container:common.containerName') - : yup.string().optional().nullable().label('container:common.containerName'), - ), - environment: uniqueKeyValuesSchema.default(null).nullable().optional().label('container:common.environment'), - routing: routingRule, - expose: exposeRule, - user: yup.number().default(null).min(UID_MIN).max(UID_MAX).nullable().optional().label('container:common.user'), - workingDirectory: yup.string().default(null).nullable().optional().label('container:common.workingDirectory'), - tty: yup.boolean().default(null).nullable().optional().label('container:common.tty'), - configContainer: configContainerRule, - ports: portConfigRule, - portRanges: portRangeConfigRule, - volumes: volumeConfigRule, - commands: shellCommandSchema.default(null).nullable().optional(), - args: shellCommandSchema.default(null).nullable().optional(), - initContainers: initContainerRule, - capabilities: uniqueKeyValuesSchema.default(null).nullable().optional().label('container:common.capabilities'), - storage: storageRule, - secrets: (secretsHaveValue ? uniqueKeyValuesSchema : uniqueKeySchema) - .default(null) - .nullable() - .optional() - .label('container:common.secrets'), +const createContainerConfigBaseSchema = (imageLabels: Record) => + yup.object().shape({ + name: matchContainerName(yup.string().nullable().optional().label('container:common.containerName')), + environment: uniqueKeyValuesSchema + .default(null) + .nullable() + .optional() + .label('container:common.environment') + .test('ruleValidation', 'errors:yup.mixed.required', testEnvironment(imageLabels)), + routing: routingRule, + expose: exposeRule, + user: yup.number().default(null).min(UID_MIN).max(UID_MAX).nullable().optional().label('container:common.user'), + workingDirectory: yup.string().default(null).nullable().optional().label('container:common.workingDirectory'), + tty: yup.boolean().default(null).nullable().optional().label('container:common.tty'), + configContainer: configContainerRule, + ports: portConfigRule, + portRanges: portRangeConfigRule, + volumes: volumeConfigRule, + commands: shellCommandSchema.default(null).nullable().optional(), + args: shellCommandSchema.default(null).nullable().optional(), + initContainers: initContainerRule, + capabilities: uniqueKeyValuesSchema.default(null).nullable().optional().label('container:common.capabilities'), + storage: storageRule, // dagent: logConfig: logConfigRule, @@ -581,15 +570,12 @@ const createContainerConfigBaseSchema = ( return testRules(secretRules, instance.secrets as UniqueKeyValue[], 'secret') }) -export const createConfigSchema = (type: ContainerConfigType, imageLabels: Record) => { - /** - * image/instance should require a container name - * bundle/deployment should not - * - * config bundles should also be able to store secret values (no agent key though...) - */ - - const nameRequired = type === 'image' || type === 'instance' - const secretsHaveValue = type === 'image' || type === 'deployment' - return createContainerConfigBaseSchema(imageLabels, nameRequired, secretsHaveValue) -} +export const createContainerConfigSchema = (imageLabels: Record) => + createContainerConfigBaseSchema(imageLabels).shape({ + secrets: uniqueKeySchema.default(null).nullable().optional().label('container:common.secrets'), + }) + +export const createConcreteContainerConfigSchema = (imageLabels: Record) => + createContainerConfigBaseSchema(imageLabels).shape({ + secrets: uniqueKeyValuesSchema.default(null).nullable().optional().label('container:common.secrets'), + }) diff --git a/web/crux-ui/src/validations/deployment.ts b/web/crux-ui/src/validations/deployment.ts index a6c2c4bc0..88f9eeca7 100644 --- a/web/crux-ui/src/validations/deployment.ts +++ b/web/crux-ui/src/validations/deployment.ts @@ -1,6 +1,6 @@ import yup from './yup' import { nameRule } from './common' -import { createConfigSchema, uniqueKeyValuesSchema } from './container' +import { createConcreteContainerConfigSchema, uniqueKeyValuesSchema } from './container' export const prefixRule = yup .string() @@ -41,7 +41,7 @@ export const startDeploymentSchema = yup.object({ instances: yup .array( yup.object().shape({ - config: createConfigSchema('instance', null), + config: createConcreteContainerConfigSchema(null), }), ) .ensure() diff --git a/web/crux-ui/src/validations/image.ts b/web/crux-ui/src/validations/image.ts index d48c673ec..1acd108e2 100644 --- a/web/crux-ui/src/validations/image.ts +++ b/web/crux-ui/src/validations/image.ts @@ -1,8 +1,8 @@ import { ContainerConfigData } from '@app/models' import yup from './yup' import { ErrorWithPath, getValidationError } from './common' +import { createContainerConfigSchema } from './container' import { Translate } from 'next-translate' -import { createConfigSchema } from './container' export type ContainerConfigValidationErrors = Record @@ -23,7 +23,7 @@ export const getContainerConfigFieldErrors = ( imageLabels: Record, t: Translate, ): ContainerConfigValidationErrors => - getConfigFieldErrorsForSchema(createConfigSchema('image', imageLabels), newConfig, t) + getConfigFieldErrorsForSchema(createContainerConfigSchema(imageLabels), newConfig, t) export const jsonErrorOf = (fieldErrors: ContainerConfigValidationErrors) => { const entries = Object.entries(fieldErrors) diff --git a/web/crux-ui/src/validations/index.ts b/web/crux-ui/src/validations/index.ts index 0f2a2ccfe..3bc7b0beb 100644 --- a/web/crux-ui/src/validations/index.ts +++ b/web/crux-ui/src/validations/index.ts @@ -4,6 +4,7 @@ export * from './config-bundle' export * from './container' export * from './deployment' export * from './image' +export * from './instance' export * from './node' export * from './notification' export * from './pipeline' diff --git a/web/crux-ui/src/validations/instance.ts b/web/crux-ui/src/validations/instance.ts new file mode 100644 index 000000000..e4f038f64 --- /dev/null +++ b/web/crux-ui/src/validations/instance.ts @@ -0,0 +1,12 @@ +import { ConcreteContainerConfigData } from '@app/models' +import { Translate } from 'next-translate' +import { getConfigFieldErrorsForSchema, ContainerConfigValidationErrors } from './image' +import { createConcreteContainerConfigSchema } from './container' + +// eslint-disable-next-line import/prefer-default-export +export const getConcreteContainerConfigFieldErrors = ( + newConfig: ConcreteContainerConfigData, + validation: Record, + t: Translate, +): ContainerConfigValidationErrors => + getConfigFieldErrorsForSchema(createConcreteContainerConfigSchema(validation), newConfig, t) diff --git a/web/crux/package.json b/web/crux/package.json index 4c92c568b..936f80181 100644 --- a/web/crux/package.json +++ b/web/crux/package.json @@ -1,6 +1,6 @@ { "name": "crux", - "version": "0.14.1", + "version": "0.15.0-rc", "description": "Open-source delivery platform that helps developers to deliver applications efficiently by simplifying software releases and operations in any environment.", "author": "dyrector.io", "private": true, diff --git a/web/crux/proto/agent.proto b/web/crux/proto/agent.proto index 8b6e43eb4..57d949f53 100644 --- a/web/crux/proto/agent.proto +++ b/web/crux/proto/agent.proto @@ -231,18 +231,17 @@ message CommonContainerConfig { message DeployWorkloadRequest { string id = 1; - string containerName = 2; /* ContainerConfigs */ - optional CommonContainerConfig common = 3; - optional DagentContainerConfig dagent = 4; - optional CraneContainerConfig crane = 5; + optional CommonContainerConfig common = 2; + optional DagentContainerConfig dagent = 3; + optional CraneContainerConfig crane = 4; - optional string registry = 6; - string imageName = 7; - string tag = 8; + optional string registry = 5; + string imageName = 6; + string tag = 7; - optional RegistryAuth registryAuth = 9; + optional RegistryAuth registryAuth = 8; } message ContainerStateRequest { diff --git a/web/crux/src/app/container/container-config.service.ts b/web/crux/src/app/container/container-config.service.ts index f0c05a9bd..0c736e400 100644 --- a/web/crux/src/app/container/container-config.service.ts +++ b/web/crux/src/app/container/container-config.service.ts @@ -259,7 +259,17 @@ export default class ContainerConfigService { }) } - const data: ContainerConfigData = req.config ?? {} + const config = await this.prisma.containerConfig.findUnique({ + where: { + id: configId, + }, + }) + + const data: ContainerConfigData = this.mapper.configDtoToConfigData( + config as any as ContainerConfigData, + req.config ?? {}, + ) + if (req.resetSection) { data[req.resetSection] = null } diff --git a/web/crux/src/app/deploy/deploy.service.ts b/web/crux/src/app/deploy/deploy.service.ts index 920306862..b62910195 100644 --- a/web/crux/src/app/deploy/deploy.service.ts +++ b/web/crux/src/app/deploy/deploy.service.ts @@ -585,7 +585,6 @@ export default class DeployService { crane: this.mapper.craneConfigToAgentProto(config), dagent: this.mapper.dagentConfigToAgentProto(config), id: it.id, - containerName: it.image.config.name, imageName: it.image.name, tag: it.image.tag, registry: registryUrl, diff --git a/web/crux/src/app/image/image.service.ts b/web/crux/src/app/image/image.service.ts index b16bdaa6e..fd63f8e21 100644 --- a/web/crux/src/app/image/image.service.ts +++ b/web/crux/src/app/image/image.service.ts @@ -123,12 +123,7 @@ export default class ImageService { data: { registry: { connect: { id: registyImages.registryId } }, version: { connect: { id: versionId } }, - config: { - create: { - type: 'image', - name: imageName, - }, - }, + config: { create: { type: 'image' } }, createdBy: identity.id, name: imageName, tag: imageTag, diff --git a/web/crux/src/app/version/version.message.ts b/web/crux/src/app/version/version.message.ts index f66390e72..9dd8d1b0b 100644 --- a/web/crux/src/app/version/version.message.ts +++ b/web/crux/src/app/version/version.message.ts @@ -1,5 +1,6 @@ import { AddImagesDto, ImageDetailsDto } from '../image/image.dto' +export const WS_TYPE_GET_IMAGE = 'get-image' export type GetImageMessage = { id: string } @@ -7,6 +8,7 @@ export type GetImageMessage = { export const WS_TYPE_IMAGE = 'image' export type ImageMessage = ImageDetailsDto +export const WS_TYPE_ADD_IMAGES = 'add-images' export type AddImagesMessage = { registryImages: AddImagesDto[] } @@ -23,6 +25,7 @@ export type ImagesAddedMessage = { images: ImageDetailsDto[] } +export const WS_TYPE_DELETE_IMAGE = 'delete-image' export type DeleteImageMessage = { imageId: string } @@ -33,4 +36,5 @@ export type ImageDeletedMessage = { } export const WS_TYPE_IMAGES_WERE_REORDERED = 'images-were-reordered' +export const WS_TYPE_ORDER_IMAGES = 'order-images' export type OrderImagesMessage = string[] diff --git a/web/crux/src/app/version/version.ws.gateway.ts b/web/crux/src/app/version/version.ws.gateway.ts index 8cd1c3176..9af90dc47 100644 --- a/web/crux/src/app/version/version.ws.gateway.ts +++ b/web/crux/src/app/version/version.ws.gateway.ts @@ -36,13 +36,15 @@ import { ImageDeletedMessage, ImageMessage, ImageTagMessage, - ImagesAddedMessage, OrderImagesMessage, + WS_TYPE_ADD_IMAGES, + WS_TYPE_DELETE_IMAGE, + WS_TYPE_GET_IMAGE, WS_TYPE_IMAGE, - WS_TYPE_IMAGES_ADDED, WS_TYPE_IMAGES_WERE_REORDERED, WS_TYPE_IMAGE_DELETED, WS_TYPE_IMAGE_TAG_UPDATED, + WS_TYPE_ORDER_IMAGES, WS_TYPE_SET_IMAGE_TAG, } from './version.message' import VersionService from './version.service' @@ -114,7 +116,7 @@ export default class VersionWebSocketGateway { } @AuditLogLevel('disabled') - @SubscribeMessage('get-image') + @SubscribeMessage(WS_TYPE_GET_IMAGE) async getImage(@SocketMessage() message: GetImageMessage): Promise> { const data = await this.imageService.getImageDetails(message.id) @@ -124,27 +126,17 @@ export default class VersionWebSocketGateway { } as WsMessage } - @SubscribeMessage('add-images') + @SubscribeMessage(WS_TYPE_ADD_IMAGES) async addImages( @TeamSlug() teamSlug: string, @VersionId() versionId: string, @SocketMessage() message: AddImagesMessage, @IdentityFromSocket() identity: Identity, - @SocketSubscription() subscription: WsSubscription, ): Promise { - const images = await this.imageService.addImagesToVersion(teamSlug, versionId, message.registryImages, identity) - - const res: WsMessage = { - type: WS_TYPE_IMAGES_ADDED, - data: { - images, - }, - } - - subscription.sendToAll(res) + await this.imageService.addImagesToVersion(teamSlug, versionId, message.registryImages, identity) } - @SubscribeMessage('delete-image') + @SubscribeMessage(WS_TYPE_DELETE_IMAGE) async deleteImage( @SocketMessage() message: DeleteImageMessage, @SocketSubscription() subscription: WsSubscription, @@ -189,7 +181,7 @@ export default class VersionWebSocketGateway { } } - @SubscribeMessage('order-images') + @SubscribeMessage(WS_TYPE_ORDER_IMAGES) async orderImages( @SocketClient() client: WsClient, @SocketMessage() message: OrderImagesMessage, diff --git a/web/crux/src/config/app.config.ts b/web/crux/src/config/app.config.ts index 5816e5a36..0a64960bc 100644 --- a/web/crux/src/config/app.config.ts +++ b/web/crux/src/config/app.config.ts @@ -26,7 +26,7 @@ const configSchema = yup.object({ ENCRYPTION_DEPRECATED_KEY: encryptionKeyRule.optional(), CRUX_AGENT_ADDRESS: yup.string().required(), - CRUX_AGENT_IMAGE: yup.string().default('latest').required(), + CRUX_AGENT_IMAGE: yup.string(), AGENT_INSTALL_SCRIPT_DISABLE_PULL: yup.bool().default(false).required(), LOG_LEVEL: yup.string().oneOf(LOG_LEVEL_VALUES).required(), diff --git a/web/crux/src/domain/container.ts b/web/crux/src/domain/container.ts index 599cc7f63..bf371f100 100644 --- a/web/crux/src/domain/container.ts +++ b/web/crux/src/domain/container.ts @@ -1,4 +1,5 @@ import { NetworkMode } from '@prisma/client' +import { registryImageNameToContainerName } from './image' export const PORT_MIN = 0 export const PORT_MAX = 65535 @@ -278,4 +279,4 @@ type InstanceWithConfigAndImageConfig = { } export const nameOfInstance = (instance: InstanceWithConfigAndImageConfig) => - instance.config.name ?? instance.image.config.name ?? instance.image.name + instance.config.name ?? instance.image.config.name ?? registryImageNameToContainerName(instance.image.name) diff --git a/web/crux/src/domain/image.ts b/web/crux/src/domain/image.ts index d83e2d0cf..8eeedc01b 100644 --- a/web/crux/src/domain/image.ts +++ b/web/crux/src/domain/image.ts @@ -81,3 +81,11 @@ export const parseDyrectorioEnvRules = (labels: Record): Record< } }, {}) } + +export const registryImageNameToContainerName = (name: string) => { + if (name.includes('/')) { + return name.split('/').pop() + } + + return name +} diff --git a/web/crux/src/domain/start-deployment.ts b/web/crux/src/domain/start-deployment.ts index af52b93f3..4114a672b 100644 --- a/web/crux/src/domain/start-deployment.ts +++ b/web/crux/src/domain/start-deployment.ts @@ -1,5 +1,5 @@ import { ContainerConfig, DeploymentStatusEnum, VersionTypeEnum } from '@prisma/client' -import { ConcreteContainerConfigData, ContainerConfigData, UniqueSecretKeyValue } from './container' +import { ConcreteContainerConfigData, ContainerConfigData, UniqueSecretKeyValue, nameOfInstance } from './container' import { mergeConfigsWithConcreteConfig, mergeInstanceConfigWithDeploymentConfig } from './container-merge' import { DeploymentWithConfig } from './deployment' @@ -97,6 +97,7 @@ export const deploymentConfigOf = (deployment: DeployableDeployment): ConcreteCo type DeployableInstance = { image: { config: ContainerConfig + name: string } config: ContainerConfig } @@ -121,7 +122,14 @@ export const instanceConfigOf = ( // then we merge and override the rest with the instance config const instanceConfig = instance.config as any as ConcreteContainerConfigData - return mergeInstanceConfigWithDeploymentConfig(mergedDeploymentConfig, instanceConfig) + const result = mergeInstanceConfigWithDeploymentConfig(mergedDeploymentConfig, instanceConfig) + + // set defaults + if (!result.name) { + result.name = nameOfInstance(instance) + } + + return result } type SecretCandidate = { diff --git a/web/crux/src/grpc/protobuf/proto/agent.ts b/web/crux/src/grpc/protobuf/proto/agent.ts index b3ce694c6..30e29af90 100644 --- a/web/crux/src/grpc/protobuf/proto/agent.ts +++ b/web/crux/src/grpc/protobuf/proto/agent.ts @@ -328,7 +328,6 @@ export interface CommonContainerConfig_SecretsEntry { export interface DeployWorkloadRequest { id: string - containerName: string /** ContainerConfigs */ common?: CommonContainerConfig | undefined dagent?: DagentContainerConfig | undefined @@ -1336,14 +1335,13 @@ export const CommonContainerConfig_SecretsEntry = { } function createBaseDeployWorkloadRequest(): DeployWorkloadRequest { - return { id: '', containerName: '', imageName: '', tag: '' } + return { id: '', imageName: '', tag: '' } } export const DeployWorkloadRequest = { fromJSON(object: any): DeployWorkloadRequest { return { id: isSet(object.id) ? String(object.id) : '', - containerName: isSet(object.containerName) ? String(object.containerName) : '', common: isSet(object.common) ? CommonContainerConfig.fromJSON(object.common) : undefined, dagent: isSet(object.dagent) ? DagentContainerConfig.fromJSON(object.dagent) : undefined, crane: isSet(object.crane) ? CraneContainerConfig.fromJSON(object.crane) : undefined, @@ -1357,7 +1355,6 @@ export const DeployWorkloadRequest = { toJSON(message: DeployWorkloadRequest): unknown { const obj: any = {} message.id !== undefined && (obj.id = message.id) - message.containerName !== undefined && (obj.containerName = message.containerName) message.common !== undefined && (obj.common = message.common ? CommonContainerConfig.toJSON(message.common) : undefined) message.dagent !== undefined &&