From d3abc9dfefcb3f7b8de98806b8fa9fdaa0aaaa7d Mon Sep 17 00:00:00 2001 From: Parthvi Vala Date: Wed, 16 Feb 2022 19:39:02 +0530 Subject: [PATCH] Add new methods to DevfileData interface Signed-off-by: Parthvi Vala --- pkg/devfile/parser/configurables.go | 234 +------ pkg/devfile/parser/configurables_test.go | 359 ---------- pkg/devfile/parser/data/interface.go | 6 + pkg/devfile/parser/data/mock_interface.go | 573 ++++++++------- pkg/devfile/parser/data/v2/containers.go | 265 +++++++ pkg/devfile/parser/data/v2/containers_test.go | 662 ++++++++++++++++++ 6 files changed, 1251 insertions(+), 848 deletions(-) delete mode 100644 pkg/devfile/parser/configurables_test.go create mode 100644 pkg/devfile/parser/data/v2/containers.go create mode 100644 pkg/devfile/parser/data/v2/containers_test.go diff --git a/pkg/devfile/parser/configurables.go b/pkg/devfile/parser/configurables.go index b5e4483c..e05b4646 100644 --- a/pkg/devfile/parser/configurables.go +++ b/pkg/devfile/parser/configurables.go @@ -1,13 +1,8 @@ package parser import ( - "fmt" - "strconv" - "strings" - v1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" "github.com/devfile/library/pkg/devfile/parser/data/v2/common" - corev1 "k8s.io/api/core/v1" ) const ( @@ -31,35 +26,20 @@ func (d DevfileObj) SetMetadataName(name string) error { // it adds the envirnoment variables to a given container name, and writes to the devfile // Example of containerEnvMap : {"runtime": {{Name: "Foo", Value: "Bar"}}} func (d DevfileObj) AddEnvVars(containerEnvMap map[string][]v1.EnvVar) error { - components, err := d.Data.GetComponents(common.DevfileOptions{}) + err := d.Data.AddEnvVars(containerEnvMap) if err != nil { return err } - for _, component := range components { - if component.Container != nil { - component.Container.Env = Merge(component.Container.Env, containerEnvMap[component.Name]) - d.Data.UpdateComponent(component) - } - } return d.WriteYamlDevfile() } // RemoveEnvVars accepts a map of container name mapped to an array of environment variables to be removed; // it removes the env vars from the specified container name and writes it to the devfile func (d DevfileObj) RemoveEnvVars(containerEnvMap map[string][]string) (err error) { - components, err := d.Data.GetComponents(common.DevfileOptions{}) + err = d.Data.RemoveEnvVars(containerEnvMap) if err != nil { return err } - for _, component := range components { - if component.Container != nil { - component.Container.Env, err = RemoveEnvVarsFromList(component.Container.Env, containerEnvMap[component.Name]) - if err != nil { - return err - } - d.Data.UpdateComponent(component) - } - } return d.WriteYamlDevfile() } @@ -67,20 +47,10 @@ func (d DevfileObj) RemoveEnvVars(containerEnvMap map[string][]string) (err erro // it converts ports to endpoints, sets the endpoint to a given container name, and writes to the devfile // Example of containerPortsMap: {"runtime": {"8080", "9000"}, "wildfly": {"12956"}} func (d DevfileObj) SetPorts(containerPortsMap map[string][]string) error { - components, err := d.Data.GetComponents(common.DevfileOptions{}) + err := d.Data.SetPorts(containerPortsMap) if err != nil { return err } - for _, component := range components { - endpoints, err := portsToEndpoints(containerPortsMap[component.Name]...) - if err != nil { - return err - } - if component.Container != nil { - component.Container.Endpoints = addEndpoints(component.Container.Endpoints, endpoints) - d.Data.UpdateComponent(component) - } - } return d.WriteYamlDevfile() } @@ -88,19 +58,10 @@ func (d DevfileObj) SetPorts(containerPortsMap map[string][]string) error { // it removes the container endpoints with the specified port numbers of the specified container, and writes to the devfile // Example of containerPortsMap: {"runtime": {"8080", "9000"}, "wildfly": {"12956"}} func (d DevfileObj) RemovePorts(containerPortsMap map[string][]string) error { - components, err := d.Data.GetComponents(common.DevfileOptions{}) + err := d.Data.RemovePorts(containerPortsMap) if err != nil { return err } - for _, component := range components { - if component.Container != nil { - component.Container.Endpoints, err = RemovePortsFromList(component.Container.Endpoints, containerPortsMap[component.Name]) - if err != nil { - return err - } - d.Data.UpdateComponent(component) - } - } return d.WriteYamlDevfile() } @@ -156,190 +117,3 @@ func (d DevfileObj) GetMemory() string { func (d DevfileObj) GetMetadataName() string { return d.Data.GetMetadata().Name } - -func portsToEndpoints(ports ...string) ([]v1.Endpoint, error) { - var endpoints []v1.Endpoint - conPorts, err := GetContainerPortsFromStrings(ports) - if err != nil { - return nil, err - } - for _, port := range conPorts { - - endpoint := v1.Endpoint{ - Name: fmt.Sprintf("port-%d-%s", port.ContainerPort, strings.ToLower(string(port.Protocol))), - TargetPort: int(port.ContainerPort), - Protocol: v1.EndpointProtocol(strings.ToLower(string(port.Protocol))), - } - endpoints = append(endpoints, endpoint) - } - return endpoints, nil - -} - -func addEndpoints(current []v1.Endpoint, other []v1.Endpoint) []v1.Endpoint { - newList := make([]v1.Endpoint, len(current)) - copy(newList, current) - for _, ep := range other { - present := false - - for _, presentep := range newList { - - protocol := presentep.Protocol - if protocol == "" { - // endpoint protocol default value is http - protocol = "http" - } - // if the target port and protocol match, we add a case where the protocol is not provided and hence we assume that to be "tcp" - if presentep.TargetPort == ep.TargetPort && (ep.Protocol == protocol) { - present = true - break - } - } - if !present { - newList = append(newList, ep) - } - } - - return newList -} - -// GetContainerPortsFromStrings generates ContainerPort values from the array of string port values -// ports is the array containing the string port values -func GetContainerPortsFromStrings(ports []string) ([]corev1.ContainerPort, error) { - var containerPorts []corev1.ContainerPort - for _, port := range ports { - splits := strings.Split(port, "/") - if len(splits) < 1 || len(splits) > 2 { - return nil, fmt.Errorf("unable to parse the port string %s", port) - } - - portNumberI64, err := strconv.ParseInt(splits[0], 10, 32) - if err != nil { - return nil, fmt.Errorf("invalid port number %s", splits[0]) - } - portNumber := int32(portNumberI64) - - var portProto corev1.Protocol - if len(splits) == 2 { - switch strings.ToUpper(splits[1]) { - case "TCP": - portProto = corev1.ProtocolTCP - case "UDP": - portProto = corev1.ProtocolUDP - default: - return nil, fmt.Errorf("invalid port protocol %s", splits[1]) - } - } else { - portProto = corev1.ProtocolTCP - } - - port := corev1.ContainerPort{ - Name: fmt.Sprintf("%d-%s", portNumber, strings.ToLower(string(portProto))), - ContainerPort: portNumber, - Protocol: portProto, - } - containerPorts = append(containerPorts, port) - } - return containerPorts, nil -} - -// RemovePortsFromList removes the ports from a given Endpoint list based on the provided port numbers -// and returns a new list of Endpoint -func RemovePortsFromList(endpoints []v1.Endpoint, ports []string) ([]v1.Endpoint, error) { - // convert the array of Endpoint to a map such that it can easily search for port(s) - // to remove from the component - portInEndpoint := map[string]bool{} - for _, ep := range endpoints { - port := strconv.Itoa(ep.TargetPort) - if !portInEndpoint[port] { - portInEndpoint[port] = true - } - } - - // convert the array of ports to a map so that it can do a fast search for port(s) - // to remove from the component - portsToBeRemoved := map[string]bool{} - - // now check if the port(s) requested for removal exists in - // the ports currently present in the component; - // if a port requested for removal is not currently present, then raise an error - // else add the port to the portsToBeRemoved map - for _, port := range ports { - if !portInEndpoint[port] { - return nil, fmt.Errorf("unable to find port %q in the component", port) - } - portsToBeRemoved[port] = true - } - - // finally, let's remove the port(s) requested by the user - newEndpointsList := []v1.Endpoint{} - for _, ep := range endpoints { - // if the port is in the port(s)(to be removed), we skip it - if portsToBeRemoved[strconv.Itoa(ep.TargetPort)] { - continue - } - newEndpointsList = append(newEndpointsList, ep) - } - return newEndpointsList, nil -} - -// RemoveEnvVarsFromList removes the env variables based on the keys provided -// and returns a new EnvVarList -func RemoveEnvVarsFromList(envVarList []v1.EnvVar, keys []string) ([]v1.EnvVar, error) { - // convert the array of envVarList to a map such that it can easily search for env var(s) - // to remove from the component - envVarListMap := map[string]bool{} - for _, env := range envVarList { - if !envVarListMap[env.Name] { - envVarListMap[env.Name] = true - } - } - - // convert the array of keys to a map so that it can do a fast search for environment variable(s) - // to remove from the component - envVarToBeRemoved := map[string]bool{} - // now check if the environment variable(s) requested for removal exists in - // the env vars currently set in the component - // if an env var requested for removal is not currently set, then raise an error - // else add the env var to the envVarToBeRemoved map - for _, key := range keys { - if !envVarListMap[key] { - return nil, fmt.Errorf("unable to find environment variable %s in the component", key) - } - envVarToBeRemoved[key] = true - } - - // finally, let's remove the environment variables(s) requested by the user - newEnvVarList := []v1.EnvVar{} - for _, envVar := range envVarList { - // if the env is in the keys(env var(s) to be removed), we skip it - if envVarToBeRemoved[envVar.Name] { - continue - } - newEnvVarList = append(newEnvVarList, envVar) - } - return newEnvVarList, nil -} - -// Merge merges the other EnvVarlist with keeping last value for duplicate EnvVars -// and returns a new EnvVarList -func Merge(original []v1.EnvVar, other []v1.EnvVar) []v1.EnvVar { - - var dedupNewEvl []v1.EnvVar - newEvl := append(original, other...) - uniqueMap := make(map[string]string) - // last value will be kept in case of duplicate env vars - for _, envVar := range newEvl { - uniqueMap[envVar.Name] = envVar.Value - } - - for key, value := range uniqueMap { - dedupNewEvl = append(dedupNewEvl, v1.EnvVar{ - Name: key, - Value: value, - }) - } - - return dedupNewEvl - -} diff --git a/pkg/devfile/parser/configurables_test.go b/pkg/devfile/parser/configurables_test.go deleted file mode 100644 index 8fc39c8a..00000000 --- a/pkg/devfile/parser/configurables_test.go +++ /dev/null @@ -1,359 +0,0 @@ -package parser - -import ( - "reflect" - "testing" - - v1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" - devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" - v2 "github.com/devfile/library/pkg/devfile/parser/data/v2" - "github.com/devfile/library/pkg/testingutil/filesystem" - "github.com/kylelemons/godebug/pretty" -) - -func TestAddAndRemoveEnvVars(t *testing.T) { - - // Use fakeFs - fs := filesystem.NewFakeFs() - - tests := []struct { - name string - listToAdd map[string][]v1.EnvVar - listToRemove map[string][]string - currentDevfile DevfileObj - wantDevFile DevfileObj - wantRemoveErr bool - }{ - { - name: "add and remove env vars", - listToAdd: map[string][]v1.EnvVar{ - "runtime": { - { - Name: "DATABASE_PASSWORD", - Value: "苦痛", - }, - }, - "loadbalancer": { - { - Name: "DATABASE_PASSWORD", - Value: "苦痛", - }, - }, - }, - listToRemove: map[string][]string{ - "loadbalancer": { - "DATABASE_PASSWORD", - }, - }, - currentDevfile: testDevfileObj(fs), - wantDevFile: DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - }, - Components: []v1.Component{ - { - Name: "runtime", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: "quay.io/nodejs-12", - Env: []v1.EnvVar{ - { - Name: "DATABASE_PASSWORD", - Value: "苦痛", - }, - }, - }, - Endpoints: []v1.Endpoint{ - { - Name: "port-3030", - TargetPort: 3030, - }, - }, - }, - }, - }, - { - Name: "loadbalancer", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: "quay.io/nginx", - Env: []v1.EnvVar{}, - }, - }, - }, - }, - }, - Events: &v1.Events{ - DevWorkspaceEvents: v1.DevWorkspaceEvents{ - PostStop: []string{"post-stop"}, - }, - }, - Projects: []v1.Project{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []v1.StarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "remove non-existent env vars", - listToAdd: map[string][]v1.EnvVar{ - "runtime": { - { - Name: "DATABASE_PASSWORD", - Value: "苦痛", - }, - }, - }, - listToRemove: map[string][]string{ - "runtime": { - "NON_EXISTENT_KEY", - }, - }, - currentDevfile: testDevfileObj(fs), - wantRemoveErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - err := tt.currentDevfile.AddEnvVars(tt.listToAdd) - - if err != nil { - t.Errorf("TestAddAndRemoveEnvVars() unexpected error while adding env vars %+v", err.Error()) - } - - err = tt.currentDevfile.RemoveEnvVars(tt.listToRemove) - - if (err != nil) != tt.wantRemoveErr { - t.Errorf("TestAddAndRemoveEnvVars() unexpected error while removing env vars %+v", err.Error()) - } - - if !tt.wantRemoveErr && !reflect.DeepEqual(tt.currentDevfile.Data, tt.wantDevFile.Data) { - t.Errorf("TestAddAndRemoveEnvVars() error: wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile.Data, tt.wantDevFile.Data)) - } - - }) - } - -} - -func TestSetAndRemovePorts(t *testing.T) { - - // Use fakeFs - fs := filesystem.NewFakeFs() - - tests := []struct { - name string - portToSet map[string][]string - portToRemove map[string][]string - currentDevfile DevfileObj - wantDevFile DevfileObj - wantRemoveErr bool - }{ - { - name: "add and remove ports", - portToSet: map[string][]string{"runtime": {"9000"}, "loadbalancer": {"8000"}}, - portToRemove: map[string][]string{"runtime": {"3030"}}, - currentDevfile: testDevfileObj(fs), - wantDevFile: DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - }, - Components: []v1.Component{ - { - Name: "runtime", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: "quay.io/nodejs-12", - }, - Endpoints: []v1.Endpoint{ - { - Name: "port-9000-tcp", - TargetPort: 9000, - Protocol: "tcp", - }, - }, - }, - }, - }, - { - Name: "loadbalancer", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: "quay.io/nginx", - }, - Endpoints: []v1.Endpoint{ - { - Name: "port-8000-tcp", - TargetPort: 8000, - Protocol: "tcp", - }, - }, - }, - }, - }, - }, - Events: &v1.Events{ - DevWorkspaceEvents: v1.DevWorkspaceEvents{ - PostStop: []string{"post-stop"}, - }, - }, - Projects: []v1.Project{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []v1.StarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "remove non-existent ports", - portToSet: map[string][]string{"runtime": {"9000"}}, - portToRemove: map[string][]string{"runtime": {"3050"}}, - currentDevfile: testDevfileObj(fs), - wantRemoveErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - err := tt.currentDevfile.SetPorts(tt.portToSet) - - if err != nil { - t.Errorf("TestSetAndRemovePorts() unexpected error while adding ports %+v", err.Error()) - } - - err = tt.currentDevfile.RemovePorts(tt.portToRemove) - - if (err != nil) != tt.wantRemoveErr { - t.Errorf("TestSetAndRemovePorts() unexpected error while removing ports %+v", err.Error()) - } - - if !tt.wantRemoveErr && !reflect.DeepEqual(tt.currentDevfile.Data, tt.wantDevFile.Data) { - t.Errorf("TestSetAndRemovePorts() error: wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile.Data, tt.wantDevFile.Data)) - } - }) - } - -} - -func testDevfileObj(fs filesystem.Filesystem) DevfileObj { - return DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - }, - Components: []v1.Component{ - { - Name: "runtime", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: "quay.io/nodejs-12", - }, - Endpoints: []v1.Endpoint{ - { - Name: "port-3030", - TargetPort: 3030, - }, - }, - }, - }, - }, - { - Name: "loadbalancer", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: "quay.io/nginx", - }, - }, - }, - }, - }, - Events: &v1.Events{ - DevWorkspaceEvents: v1.DevWorkspaceEvents{ - PostStop: []string{"post-stop"}, - }, - }, - Projects: []v1.Project{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []v1.StarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - }, - }, - }, - } -} diff --git a/pkg/devfile/parser/data/interface.go b/pkg/devfile/parser/data/interface.go index 5721ca1d..743077e8 100644 --- a/pkg/devfile/parser/data/interface.go +++ b/pkg/devfile/parser/data/interface.go @@ -82,4 +82,10 @@ type DevfileData interface { GetDevfileContainerComponents(common.DevfileOptions) ([]v1.Component, error) GetDevfileVolumeComponents(common.DevfileOptions) ([]v1.Component, error) + + // containers + RemoveEnvVars(containerEnvMap map[string][]string) error + SetPorts(containerPortsMap map[string][]string) error + AddEnvVars(containerEnvMap map[string][]v1.EnvVar) error + RemovePorts(containerPortsMap map[string][]string) error } diff --git a/pkg/devfile/parser/data/mock_interface.go b/pkg/devfile/parser/data/mock_interface.go index 89951d41..4439c9b5 100644 --- a/pkg/devfile/parser/data/mock_interface.go +++ b/pkg/devfile/parser/data/mock_interface.go @@ -5,396 +5,455 @@ package data import ( - reflect "reflect" - v1alpha2 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" attributes "github.com/devfile/api/v2/pkg/attributes" devfile "github.com/devfile/api/v2/pkg/devfile" common "github.com/devfile/library/pkg/devfile/parser/data/v2/common" gomock "github.com/golang/mock/gomock" + reflect "reflect" ) -// MockDevfileData is a mock of DevfileData interface. +// MockDevfileData is a mock of DevfileData interface type MockDevfileData struct { ctrl *gomock.Controller recorder *MockDevfileDataMockRecorder } -// MockDevfileDataMockRecorder is the mock recorder for MockDevfileData. +// MockDevfileDataMockRecorder is the mock recorder for MockDevfileData type MockDevfileDataMockRecorder struct { mock *MockDevfileData } -// NewMockDevfileData creates a new mock instance. +// NewMockDevfileData creates a new mock instance func NewMockDevfileData(ctrl *gomock.Controller) *MockDevfileData { mock := &MockDevfileData{ctrl: ctrl} mock.recorder = &MockDevfileDataMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use. +// EXPECT returns an object that allows the caller to indicate expected use func (m *MockDevfileData) EXPECT() *MockDevfileDataMockRecorder { return m.recorder } -// AddAttributes mocks base method. -func (m *MockDevfileData) AddAttributes(key string, value interface{}) error { +// GetSchemaVersion mocks base method +func (m *MockDevfileData) GetSchemaVersion() string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddAttributes", key, value) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "GetSchemaVersion") + ret0, _ := ret[0].(string) return ret0 } -// AddAttributes indicates an expected call of AddAttributes. -func (mr *MockDevfileDataMockRecorder) AddAttributes(key, value interface{}) *gomock.Call { +// GetSchemaVersion indicates an expected call of GetSchemaVersion +func (mr *MockDevfileDataMockRecorder) GetSchemaVersion() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAttributes", reflect.TypeOf((*MockDevfileData)(nil).AddAttributes), key, value) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchemaVersion", reflect.TypeOf((*MockDevfileData)(nil).GetSchemaVersion)) } -// AddCommands mocks base method. -func (m *MockDevfileData) AddCommands(commands []v1alpha2.Command) error { +// SetSchemaVersion mocks base method +func (m *MockDevfileData) SetSchemaVersion(version string) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddCommands", commands) - ret0, _ := ret[0].(error) - return ret0 + m.ctrl.Call(m, "SetSchemaVersion", version) } -// AddCommands indicates an expected call of AddCommands. -func (mr *MockDevfileDataMockRecorder) AddCommands(commands interface{}) *gomock.Call { +// SetSchemaVersion indicates an expected call of SetSchemaVersion +func (mr *MockDevfileDataMockRecorder) SetSchemaVersion(version interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCommands", reflect.TypeOf((*MockDevfileData)(nil).AddCommands), commands) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSchemaVersion", reflect.TypeOf((*MockDevfileData)(nil).SetSchemaVersion), version) } -// AddComponents mocks base method. -func (m *MockDevfileData) AddComponents(components []v1alpha2.Component) error { +// GetMetadata mocks base method +func (m *MockDevfileData) GetMetadata() devfile.DevfileMetadata { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddComponents", components) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "GetMetadata") + ret0, _ := ret[0].(devfile.DevfileMetadata) return ret0 } -// AddComponents indicates an expected call of AddComponents. -func (mr *MockDevfileDataMockRecorder) AddComponents(components interface{}) *gomock.Call { +// GetMetadata indicates an expected call of GetMetadata +func (mr *MockDevfileDataMockRecorder) GetMetadata() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddComponents", reflect.TypeOf((*MockDevfileData)(nil).AddComponents), components) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadata", reflect.TypeOf((*MockDevfileData)(nil).GetMetadata)) } -// AddEvents mocks base method. -func (m *MockDevfileData) AddEvents(events v1alpha2.Events) error { +// SetMetadata mocks base method +func (m *MockDevfileData) SetMetadata(metadata devfile.DevfileMetadata) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddEvents", events) - ret0, _ := ret[0].(error) - return ret0 + m.ctrl.Call(m, "SetMetadata", metadata) } -// AddEvents indicates an expected call of AddEvents. -func (mr *MockDevfileDataMockRecorder) AddEvents(events interface{}) *gomock.Call { +// SetMetadata indicates an expected call of SetMetadata +func (mr *MockDevfileDataMockRecorder) SetMetadata(metadata interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddEvents", reflect.TypeOf((*MockDevfileData)(nil).AddEvents), events) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMetadata", reflect.TypeOf((*MockDevfileData)(nil).SetMetadata), metadata) } -// AddProjects mocks base method. -func (m *MockDevfileData) AddProjects(projects []v1alpha2.Project) error { +// GetAttributes mocks base method +func (m *MockDevfileData) GetAttributes() (attributes.Attributes, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddProjects", projects) + ret := m.ctrl.Call(m, "GetAttributes") + ret0, _ := ret[0].(attributes.Attributes) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAttributes indicates an expected call of GetAttributes +func (mr *MockDevfileDataMockRecorder) GetAttributes() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAttributes", reflect.TypeOf((*MockDevfileData)(nil).GetAttributes)) +} + +// AddAttributes mocks base method +func (m *MockDevfileData) AddAttributes(key string, value interface{}) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddAttributes", key, value) ret0, _ := ret[0].(error) return ret0 } -// AddProjects indicates an expected call of AddProjects. -func (mr *MockDevfileDataMockRecorder) AddProjects(projects interface{}) *gomock.Call { +// AddAttributes indicates an expected call of AddAttributes +func (mr *MockDevfileDataMockRecorder) AddAttributes(key, value interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddProjects", reflect.TypeOf((*MockDevfileData)(nil).AddProjects), projects) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAttributes", reflect.TypeOf((*MockDevfileData)(nil).AddAttributes), key, value) } -// AddStarterProjects mocks base method. -func (m *MockDevfileData) AddStarterProjects(projects []v1alpha2.StarterProject) error { +// UpdateAttributes mocks base method +func (m *MockDevfileData) UpdateAttributes(key string, value interface{}) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddStarterProjects", projects) + ret := m.ctrl.Call(m, "UpdateAttributes", key, value) ret0, _ := ret[0].(error) return ret0 } -// AddStarterProjects indicates an expected call of AddStarterProjects. -func (mr *MockDevfileDataMockRecorder) AddStarterProjects(projects interface{}) *gomock.Call { +// UpdateAttributes indicates an expected call of UpdateAttributes +func (mr *MockDevfileDataMockRecorder) UpdateAttributes(key, value interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddStarterProjects", reflect.TypeOf((*MockDevfileData)(nil).AddStarterProjects), projects) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAttributes", reflect.TypeOf((*MockDevfileData)(nil).UpdateAttributes), key, value) } -// AddVolumeMounts mocks base method. -func (m *MockDevfileData) AddVolumeMounts(containerName string, volumeMounts []v1alpha2.VolumeMount) error { +// GetParent mocks base method +func (m *MockDevfileData) GetParent() *v1alpha2.Parent { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddVolumeMounts", containerName, volumeMounts) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "GetParent") + ret0, _ := ret[0].(*v1alpha2.Parent) return ret0 } -// AddVolumeMounts indicates an expected call of AddVolumeMounts. -func (mr *MockDevfileDataMockRecorder) AddVolumeMounts(containerName, volumeMounts interface{}) *gomock.Call { +// GetParent indicates an expected call of GetParent +func (mr *MockDevfileDataMockRecorder) GetParent() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddVolumeMounts", reflect.TypeOf((*MockDevfileData)(nil).AddVolumeMounts), containerName, volumeMounts) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParent", reflect.TypeOf((*MockDevfileData)(nil).GetParent)) } -// DeleteCommand mocks base method. -func (m *MockDevfileData) DeleteCommand(id string) error { +// SetParent mocks base method +func (m *MockDevfileData) SetParent(parent *v1alpha2.Parent) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteCommand", id) - ret0, _ := ret[0].(error) + m.ctrl.Call(m, "SetParent", parent) +} + +// SetParent indicates an expected call of SetParent +func (mr *MockDevfileDataMockRecorder) SetParent(parent interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetParent", reflect.TypeOf((*MockDevfileData)(nil).SetParent), parent) +} + +// GetEvents mocks base method +func (m *MockDevfileData) GetEvents() v1alpha2.Events { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEvents") + ret0, _ := ret[0].(v1alpha2.Events) return ret0 } -// DeleteCommand indicates an expected call of DeleteCommand. -func (mr *MockDevfileDataMockRecorder) DeleteCommand(id interface{}) *gomock.Call { +// GetEvents indicates an expected call of GetEvents +func (mr *MockDevfileDataMockRecorder) GetEvents() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCommand", reflect.TypeOf((*MockDevfileData)(nil).DeleteCommand), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEvents", reflect.TypeOf((*MockDevfileData)(nil).GetEvents)) } -// DeleteComponent mocks base method. -func (m *MockDevfileData) DeleteComponent(name string) error { +// AddEvents mocks base method +func (m *MockDevfileData) AddEvents(events v1alpha2.Events) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteComponent", name) + ret := m.ctrl.Call(m, "AddEvents", events) ret0, _ := ret[0].(error) return ret0 } -// DeleteComponent indicates an expected call of DeleteComponent. -func (mr *MockDevfileDataMockRecorder) DeleteComponent(name interface{}) *gomock.Call { +// AddEvents indicates an expected call of AddEvents +func (mr *MockDevfileDataMockRecorder) AddEvents(events interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteComponent", reflect.TypeOf((*MockDevfileData)(nil).DeleteComponent), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddEvents", reflect.TypeOf((*MockDevfileData)(nil).AddEvents), events) } -// DeleteProject mocks base method. -func (m *MockDevfileData) DeleteProject(name string) error { +// UpdateEvents mocks base method +func (m *MockDevfileData) UpdateEvents(postStart, postStop, preStart, preStop []string) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteProject", name) + m.ctrl.Call(m, "UpdateEvents", postStart, postStop, preStart, preStop) +} + +// UpdateEvents indicates an expected call of UpdateEvents +func (mr *MockDevfileDataMockRecorder) UpdateEvents(postStart, postStop, preStart, preStop interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateEvents", reflect.TypeOf((*MockDevfileData)(nil).UpdateEvents), postStart, postStop, preStart, preStop) +} + +// GetComponents mocks base method +func (m *MockDevfileData) GetComponents(arg0 common.DevfileOptions) ([]v1alpha2.Component, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetComponents", arg0) + ret0, _ := ret[0].([]v1alpha2.Component) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetComponents indicates an expected call of GetComponents +func (mr *MockDevfileDataMockRecorder) GetComponents(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetComponents", reflect.TypeOf((*MockDevfileData)(nil).GetComponents), arg0) +} + +// AddComponents mocks base method +func (m *MockDevfileData) AddComponents(components []v1alpha2.Component) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddComponents", components) ret0, _ := ret[0].(error) return ret0 } -// DeleteProject indicates an expected call of DeleteProject. -func (mr *MockDevfileDataMockRecorder) DeleteProject(name interface{}) *gomock.Call { +// AddComponents indicates an expected call of AddComponents +func (mr *MockDevfileDataMockRecorder) AddComponents(components interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProject", reflect.TypeOf((*MockDevfileData)(nil).DeleteProject), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddComponents", reflect.TypeOf((*MockDevfileData)(nil).AddComponents), components) } -// DeleteStarterProject mocks base method. -func (m *MockDevfileData) DeleteStarterProject(name string) error { +// UpdateComponent mocks base method +func (m *MockDevfileData) UpdateComponent(component v1alpha2.Component) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteStarterProject", name) + ret := m.ctrl.Call(m, "UpdateComponent", component) ret0, _ := ret[0].(error) return ret0 } -// DeleteStarterProject indicates an expected call of DeleteStarterProject. -func (mr *MockDevfileDataMockRecorder) DeleteStarterProject(name interface{}) *gomock.Call { +// UpdateComponent indicates an expected call of UpdateComponent +func (mr *MockDevfileDataMockRecorder) UpdateComponent(component interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStarterProject", reflect.TypeOf((*MockDevfileData)(nil).DeleteStarterProject), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateComponent", reflect.TypeOf((*MockDevfileData)(nil).UpdateComponent), component) } -// DeleteVolumeMount mocks base method. -func (m *MockDevfileData) DeleteVolumeMount(name string) error { +// DeleteComponent mocks base method +func (m *MockDevfileData) DeleteComponent(name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteVolumeMount", name) + ret := m.ctrl.Call(m, "DeleteComponent", name) ret0, _ := ret[0].(error) return ret0 } -// DeleteVolumeMount indicates an expected call of DeleteVolumeMount. -func (mr *MockDevfileDataMockRecorder) DeleteVolumeMount(name interface{}) *gomock.Call { +// DeleteComponent indicates an expected call of DeleteComponent +func (mr *MockDevfileDataMockRecorder) DeleteComponent(name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVolumeMount", reflect.TypeOf((*MockDevfileData)(nil).DeleteVolumeMount), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteComponent", reflect.TypeOf((*MockDevfileData)(nil).DeleteComponent), name) } -// GetAttributes mocks base method. -func (m *MockDevfileData) GetAttributes() (attributes.Attributes, error) { +// GetProjects mocks base method +func (m *MockDevfileData) GetProjects(arg0 common.DevfileOptions) ([]v1alpha2.Project, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAttributes") - ret0, _ := ret[0].(attributes.Attributes) + ret := m.ctrl.Call(m, "GetProjects", arg0) + ret0, _ := ret[0].([]v1alpha2.Project) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetAttributes indicates an expected call of GetAttributes. -func (mr *MockDevfileDataMockRecorder) GetAttributes() *gomock.Call { +// GetProjects indicates an expected call of GetProjects +func (mr *MockDevfileDataMockRecorder) GetProjects(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAttributes", reflect.TypeOf((*MockDevfileData)(nil).GetAttributes)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProjects", reflect.TypeOf((*MockDevfileData)(nil).GetProjects), arg0) } -// GetCommands mocks base method. -func (m *MockDevfileData) GetCommands(arg0 common.DevfileOptions) ([]v1alpha2.Command, error) { +// AddProjects mocks base method +func (m *MockDevfileData) AddProjects(projects []v1alpha2.Project) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCommands", arg0) - ret0, _ := ret[0].([]v1alpha2.Command) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "AddProjects", projects) + ret0, _ := ret[0].(error) + return ret0 } -// GetCommands indicates an expected call of GetCommands. -func (mr *MockDevfileDataMockRecorder) GetCommands(arg0 interface{}) *gomock.Call { +// AddProjects indicates an expected call of AddProjects +func (mr *MockDevfileDataMockRecorder) AddProjects(projects interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCommands", reflect.TypeOf((*MockDevfileData)(nil).GetCommands), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddProjects", reflect.TypeOf((*MockDevfileData)(nil).AddProjects), projects) } -// GetComponents mocks base method. -func (m *MockDevfileData) GetComponents(arg0 common.DevfileOptions) ([]v1alpha2.Component, error) { +// UpdateProject mocks base method +func (m *MockDevfileData) UpdateProject(project v1alpha2.Project) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetComponents", arg0) - ret0, _ := ret[0].([]v1alpha2.Component) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "UpdateProject", project) + ret0, _ := ret[0].(error) + return ret0 } -// GetComponents indicates an expected call of GetComponents. -func (mr *MockDevfileDataMockRecorder) GetComponents(arg0 interface{}) *gomock.Call { +// UpdateProject indicates an expected call of UpdateProject +func (mr *MockDevfileDataMockRecorder) UpdateProject(project interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetComponents", reflect.TypeOf((*MockDevfileData)(nil).GetComponents), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProject", reflect.TypeOf((*MockDevfileData)(nil).UpdateProject), project) } -// GetDevfileContainerComponents mocks base method. -func (m *MockDevfileData) GetDevfileContainerComponents(arg0 common.DevfileOptions) ([]v1alpha2.Component, error) { +// DeleteProject mocks base method +func (m *MockDevfileData) DeleteProject(name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDevfileContainerComponents", arg0) - ret0, _ := ret[0].([]v1alpha2.Component) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "DeleteProject", name) + ret0, _ := ret[0].(error) + return ret0 } -// GetDevfileContainerComponents indicates an expected call of GetDevfileContainerComponents. -func (mr *MockDevfileDataMockRecorder) GetDevfileContainerComponents(arg0 interface{}) *gomock.Call { +// DeleteProject indicates an expected call of DeleteProject +func (mr *MockDevfileDataMockRecorder) DeleteProject(name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileContainerComponents", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileContainerComponents), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProject", reflect.TypeOf((*MockDevfileData)(nil).DeleteProject), name) } -// GetDevfileVolumeComponents mocks base method. -func (m *MockDevfileData) GetDevfileVolumeComponents(arg0 common.DevfileOptions) ([]v1alpha2.Component, error) { +// GetStarterProjects mocks base method +func (m *MockDevfileData) GetStarterProjects(arg0 common.DevfileOptions) ([]v1alpha2.StarterProject, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDevfileVolumeComponents", arg0) - ret0, _ := ret[0].([]v1alpha2.Component) + ret := m.ctrl.Call(m, "GetStarterProjects", arg0) + ret0, _ := ret[0].([]v1alpha2.StarterProject) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetDevfileVolumeComponents indicates an expected call of GetDevfileVolumeComponents. -func (mr *MockDevfileDataMockRecorder) GetDevfileVolumeComponents(arg0 interface{}) *gomock.Call { +// GetStarterProjects indicates an expected call of GetStarterProjects +func (mr *MockDevfileDataMockRecorder) GetStarterProjects(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileVolumeComponents", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileVolumeComponents), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStarterProjects", reflect.TypeOf((*MockDevfileData)(nil).GetStarterProjects), arg0) } -// GetDevfileWorkspaceSpec mocks base method. -func (m *MockDevfileData) GetDevfileWorkspaceSpec() *v1alpha2.DevWorkspaceTemplateSpec { +// AddStarterProjects mocks base method +func (m *MockDevfileData) AddStarterProjects(projects []v1alpha2.StarterProject) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDevfileWorkspaceSpec") - ret0, _ := ret[0].(*v1alpha2.DevWorkspaceTemplateSpec) + ret := m.ctrl.Call(m, "AddStarterProjects", projects) + ret0, _ := ret[0].(error) return ret0 } -// GetDevfileWorkspaceSpec indicates an expected call of GetDevfileWorkspaceSpec. -func (mr *MockDevfileDataMockRecorder) GetDevfileWorkspaceSpec() *gomock.Call { +// AddStarterProjects indicates an expected call of AddStarterProjects +func (mr *MockDevfileDataMockRecorder) AddStarterProjects(projects interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileWorkspaceSpec", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileWorkspaceSpec)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddStarterProjects", reflect.TypeOf((*MockDevfileData)(nil).AddStarterProjects), projects) } -// GetDevfileWorkspaceSpecContent mocks base method. -func (m *MockDevfileData) GetDevfileWorkspaceSpecContent() *v1alpha2.DevWorkspaceTemplateSpecContent { +// UpdateStarterProject mocks base method +func (m *MockDevfileData) UpdateStarterProject(project v1alpha2.StarterProject) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDevfileWorkspaceSpecContent") - ret0, _ := ret[0].(*v1alpha2.DevWorkspaceTemplateSpecContent) + ret := m.ctrl.Call(m, "UpdateStarterProject", project) + ret0, _ := ret[0].(error) return ret0 } -// GetDevfileWorkspaceSpecContent indicates an expected call of GetDevfileWorkspaceSpecContent. -func (mr *MockDevfileDataMockRecorder) GetDevfileWorkspaceSpecContent() *gomock.Call { +// UpdateStarterProject indicates an expected call of UpdateStarterProject +func (mr *MockDevfileDataMockRecorder) UpdateStarterProject(project interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileWorkspaceSpecContent", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileWorkspaceSpecContent)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStarterProject", reflect.TypeOf((*MockDevfileData)(nil).UpdateStarterProject), project) } -// GetEvents mocks base method. -func (m *MockDevfileData) GetEvents() v1alpha2.Events { +// DeleteStarterProject mocks base method +func (m *MockDevfileData) DeleteStarterProject(name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEvents") - ret0, _ := ret[0].(v1alpha2.Events) + ret := m.ctrl.Call(m, "DeleteStarterProject", name) + ret0, _ := ret[0].(error) return ret0 } -// GetEvents indicates an expected call of GetEvents. -func (mr *MockDevfileDataMockRecorder) GetEvents() *gomock.Call { +// DeleteStarterProject indicates an expected call of DeleteStarterProject +func (mr *MockDevfileDataMockRecorder) DeleteStarterProject(name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEvents", reflect.TypeOf((*MockDevfileData)(nil).GetEvents)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStarterProject", reflect.TypeOf((*MockDevfileData)(nil).DeleteStarterProject), name) } -// GetMetadata mocks base method. -func (m *MockDevfileData) GetMetadata() devfile.DevfileMetadata { +// GetCommands mocks base method +func (m *MockDevfileData) GetCommands(arg0 common.DevfileOptions) ([]v1alpha2.Command, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetadata") - ret0, _ := ret[0].(devfile.DevfileMetadata) + ret := m.ctrl.Call(m, "GetCommands", arg0) + ret0, _ := ret[0].([]v1alpha2.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCommands indicates an expected call of GetCommands +func (mr *MockDevfileDataMockRecorder) GetCommands(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCommands", reflect.TypeOf((*MockDevfileData)(nil).GetCommands), arg0) +} + +// AddCommands mocks base method +func (m *MockDevfileData) AddCommands(commands []v1alpha2.Command) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddCommands", commands) + ret0, _ := ret[0].(error) return ret0 } -// GetMetadata indicates an expected call of GetMetadata. -func (mr *MockDevfileDataMockRecorder) GetMetadata() *gomock.Call { +// AddCommands indicates an expected call of AddCommands +func (mr *MockDevfileDataMockRecorder) AddCommands(commands interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadata", reflect.TypeOf((*MockDevfileData)(nil).GetMetadata)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCommands", reflect.TypeOf((*MockDevfileData)(nil).AddCommands), commands) } -// GetParent mocks base method. -func (m *MockDevfileData) GetParent() *v1alpha2.Parent { +// UpdateCommand mocks base method +func (m *MockDevfileData) UpdateCommand(command v1alpha2.Command) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetParent") - ret0, _ := ret[0].(*v1alpha2.Parent) + ret := m.ctrl.Call(m, "UpdateCommand", command) + ret0, _ := ret[0].(error) return ret0 } -// GetParent indicates an expected call of GetParent. -func (mr *MockDevfileDataMockRecorder) GetParent() *gomock.Call { +// UpdateCommand indicates an expected call of UpdateCommand +func (mr *MockDevfileDataMockRecorder) UpdateCommand(command interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParent", reflect.TypeOf((*MockDevfileData)(nil).GetParent)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCommand", reflect.TypeOf((*MockDevfileData)(nil).UpdateCommand), command) } -// GetProjects mocks base method. -func (m *MockDevfileData) GetProjects(arg0 common.DevfileOptions) ([]v1alpha2.Project, error) { +// DeleteCommand mocks base method +func (m *MockDevfileData) DeleteCommand(id string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetProjects", arg0) - ret0, _ := ret[0].([]v1alpha2.Project) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "DeleteCommand", id) + ret0, _ := ret[0].(error) + return ret0 } -// GetProjects indicates an expected call of GetProjects. -func (mr *MockDevfileDataMockRecorder) GetProjects(arg0 interface{}) *gomock.Call { +// DeleteCommand indicates an expected call of DeleteCommand +func (mr *MockDevfileDataMockRecorder) DeleteCommand(id interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProjects", reflect.TypeOf((*MockDevfileData)(nil).GetProjects), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCommand", reflect.TypeOf((*MockDevfileData)(nil).DeleteCommand), id) } -// GetSchemaVersion mocks base method. -func (m *MockDevfileData) GetSchemaVersion() string { +// AddVolumeMounts mocks base method +func (m *MockDevfileData) AddVolumeMounts(containerName string, volumeMounts []v1alpha2.VolumeMount) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSchemaVersion") - ret0, _ := ret[0].(string) + ret := m.ctrl.Call(m, "AddVolumeMounts", containerName, volumeMounts) + ret0, _ := ret[0].(error) return ret0 } -// GetSchemaVersion indicates an expected call of GetSchemaVersion. -func (mr *MockDevfileDataMockRecorder) GetSchemaVersion() *gomock.Call { +// AddVolumeMounts indicates an expected call of AddVolumeMounts +func (mr *MockDevfileDataMockRecorder) AddVolumeMounts(containerName, volumeMounts interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchemaVersion", reflect.TypeOf((*MockDevfileData)(nil).GetSchemaVersion)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddVolumeMounts", reflect.TypeOf((*MockDevfileData)(nil).AddVolumeMounts), containerName, volumeMounts) } -// GetStarterProjects mocks base method. -func (m *MockDevfileData) GetStarterProjects(arg0 common.DevfileOptions) ([]v1alpha2.StarterProject, error) { +// DeleteVolumeMount mocks base method +func (m *MockDevfileData) DeleteVolumeMount(name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetStarterProjects", arg0) - ret0, _ := ret[0].([]v1alpha2.StarterProject) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "DeleteVolumeMount", name) + ret0, _ := ret[0].(error) + return ret0 } -// GetStarterProjects indicates an expected call of GetStarterProjects. -func (mr *MockDevfileDataMockRecorder) GetStarterProjects(arg0 interface{}) *gomock.Call { +// DeleteVolumeMount indicates an expected call of DeleteVolumeMount +func (mr *MockDevfileDataMockRecorder) DeleteVolumeMount(name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStarterProjects", reflect.TypeOf((*MockDevfileData)(nil).GetStarterProjects), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVolumeMount", reflect.TypeOf((*MockDevfileData)(nil).DeleteVolumeMount), name) } -// GetVolumeMountPaths mocks base method. +// GetVolumeMountPaths mocks base method func (m *MockDevfileData) GetVolumeMountPaths(mountName, containerName string) ([]string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetVolumeMountPaths", mountName, containerName) @@ -403,150 +462,146 @@ func (m *MockDevfileData) GetVolumeMountPaths(mountName, containerName string) ( return ret0, ret1 } -// GetVolumeMountPaths indicates an expected call of GetVolumeMountPaths. +// GetVolumeMountPaths indicates an expected call of GetVolumeMountPaths func (mr *MockDevfileDataMockRecorder) GetVolumeMountPaths(mountName, containerName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVolumeMountPaths", reflect.TypeOf((*MockDevfileData)(nil).GetVolumeMountPaths), mountName, containerName) } -// SetDevfileWorkspaceSpec mocks base method. -func (m *MockDevfileData) SetDevfileWorkspaceSpec(spec v1alpha2.DevWorkspaceTemplateSpec) { +// GetDevfileWorkspaceSpecContent mocks base method +func (m *MockDevfileData) GetDevfileWorkspaceSpecContent() *v1alpha2.DevWorkspaceTemplateSpecContent { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetDevfileWorkspaceSpec", spec) + ret := m.ctrl.Call(m, "GetDevfileWorkspaceSpecContent") + ret0, _ := ret[0].(*v1alpha2.DevWorkspaceTemplateSpecContent) + return ret0 } -// SetDevfileWorkspaceSpec indicates an expected call of SetDevfileWorkspaceSpec. -func (mr *MockDevfileDataMockRecorder) SetDevfileWorkspaceSpec(spec interface{}) *gomock.Call { +// GetDevfileWorkspaceSpecContent indicates an expected call of GetDevfileWorkspaceSpecContent +func (mr *MockDevfileDataMockRecorder) GetDevfileWorkspaceSpecContent() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDevfileWorkspaceSpec", reflect.TypeOf((*MockDevfileData)(nil).SetDevfileWorkspaceSpec), spec) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileWorkspaceSpecContent", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileWorkspaceSpecContent)) } -// SetDevfileWorkspaceSpecContent mocks base method. +// SetDevfileWorkspaceSpecContent mocks base method func (m *MockDevfileData) SetDevfileWorkspaceSpecContent(content v1alpha2.DevWorkspaceTemplateSpecContent) { m.ctrl.T.Helper() m.ctrl.Call(m, "SetDevfileWorkspaceSpecContent", content) } -// SetDevfileWorkspaceSpecContent indicates an expected call of SetDevfileWorkspaceSpecContent. +// SetDevfileWorkspaceSpecContent indicates an expected call of SetDevfileWorkspaceSpecContent func (mr *MockDevfileDataMockRecorder) SetDevfileWorkspaceSpecContent(content interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDevfileWorkspaceSpecContent", reflect.TypeOf((*MockDevfileData)(nil).SetDevfileWorkspaceSpecContent), content) } -// SetMetadata mocks base method. -func (m *MockDevfileData) SetMetadata(metadata devfile.DevfileMetadata) { +// GetDevfileWorkspaceSpec mocks base method +func (m *MockDevfileData) GetDevfileWorkspaceSpec() *v1alpha2.DevWorkspaceTemplateSpec { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetMetadata", metadata) + ret := m.ctrl.Call(m, "GetDevfileWorkspaceSpec") + ret0, _ := ret[0].(*v1alpha2.DevWorkspaceTemplateSpec) + return ret0 } -// SetMetadata indicates an expected call of SetMetadata. -func (mr *MockDevfileDataMockRecorder) SetMetadata(metadata interface{}) *gomock.Call { +// GetDevfileWorkspaceSpec indicates an expected call of GetDevfileWorkspaceSpec +func (mr *MockDevfileDataMockRecorder) GetDevfileWorkspaceSpec() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMetadata", reflect.TypeOf((*MockDevfileData)(nil).SetMetadata), metadata) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileWorkspaceSpec", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileWorkspaceSpec)) } -// SetParent mocks base method. -func (m *MockDevfileData) SetParent(parent *v1alpha2.Parent) { +// SetDevfileWorkspaceSpec mocks base method +func (m *MockDevfileData) SetDevfileWorkspaceSpec(spec v1alpha2.DevWorkspaceTemplateSpec) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetParent", parent) + m.ctrl.Call(m, "SetDevfileWorkspaceSpec", spec) } -// SetParent indicates an expected call of SetParent. -func (mr *MockDevfileDataMockRecorder) SetParent(parent interface{}) *gomock.Call { +// SetDevfileWorkspaceSpec indicates an expected call of SetDevfileWorkspaceSpec +func (mr *MockDevfileDataMockRecorder) SetDevfileWorkspaceSpec(spec interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetParent", reflect.TypeOf((*MockDevfileData)(nil).SetParent), parent) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDevfileWorkspaceSpec", reflect.TypeOf((*MockDevfileData)(nil).SetDevfileWorkspaceSpec), spec) } -// SetSchemaVersion mocks base method. -func (m *MockDevfileData) SetSchemaVersion(version string) { +// GetDevfileContainerComponents mocks base method +func (m *MockDevfileData) GetDevfileContainerComponents(arg0 common.DevfileOptions) ([]v1alpha2.Component, error) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSchemaVersion", version) + ret := m.ctrl.Call(m, "GetDevfileContainerComponents", arg0) + ret0, _ := ret[0].([]v1alpha2.Component) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// SetSchemaVersion indicates an expected call of SetSchemaVersion. -func (mr *MockDevfileDataMockRecorder) SetSchemaVersion(version interface{}) *gomock.Call { +// GetDevfileContainerComponents indicates an expected call of GetDevfileContainerComponents +func (mr *MockDevfileDataMockRecorder) GetDevfileContainerComponents(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSchemaVersion", reflect.TypeOf((*MockDevfileData)(nil).SetSchemaVersion), version) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileContainerComponents", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileContainerComponents), arg0) } -// UpdateAttributes mocks base method. -func (m *MockDevfileData) UpdateAttributes(key string, value interface{}) error { +// GetDevfileVolumeComponents mocks base method +func (m *MockDevfileData) GetDevfileVolumeComponents(arg0 common.DevfileOptions) ([]v1alpha2.Component, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateAttributes", key, value) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "GetDevfileVolumeComponents", arg0) + ret0, _ := ret[0].([]v1alpha2.Component) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// UpdateAttributes indicates an expected call of UpdateAttributes. -func (mr *MockDevfileDataMockRecorder) UpdateAttributes(key, value interface{}) *gomock.Call { +// GetDevfileVolumeComponents indicates an expected call of GetDevfileVolumeComponents +func (mr *MockDevfileDataMockRecorder) GetDevfileVolumeComponents(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAttributes", reflect.TypeOf((*MockDevfileData)(nil).UpdateAttributes), key, value) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDevfileVolumeComponents", reflect.TypeOf((*MockDevfileData)(nil).GetDevfileVolumeComponents), arg0) } -// UpdateCommand mocks base method. -func (m *MockDevfileData) UpdateCommand(command v1alpha2.Command) error { +// RemoveEnvVars mocks base method +func (m *MockDevfileData) RemoveEnvVars(containerEnvMap map[string][]string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateCommand", command) + ret := m.ctrl.Call(m, "RemoveEnvVars", containerEnvMap) ret0, _ := ret[0].(error) return ret0 } -// UpdateCommand indicates an expected call of UpdateCommand. -func (mr *MockDevfileDataMockRecorder) UpdateCommand(command interface{}) *gomock.Call { +// RemoveEnvVars indicates an expected call of RemoveEnvVars +func (mr *MockDevfileDataMockRecorder) RemoveEnvVars(containerEnvMap interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCommand", reflect.TypeOf((*MockDevfileData)(nil).UpdateCommand), command) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveEnvVars", reflect.TypeOf((*MockDevfileData)(nil).RemoveEnvVars), containerEnvMap) } -// UpdateComponent mocks base method. -func (m *MockDevfileData) UpdateComponent(component v1alpha2.Component) error { +// SetPorts mocks base method +func (m *MockDevfileData) SetPorts(containerPortsMap map[string][]string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateComponent", component) + ret := m.ctrl.Call(m, "SetPorts", containerPortsMap) ret0, _ := ret[0].(error) return ret0 } -// UpdateComponent indicates an expected call of UpdateComponent. -func (mr *MockDevfileDataMockRecorder) UpdateComponent(component interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateComponent", reflect.TypeOf((*MockDevfileData)(nil).UpdateComponent), component) -} - -// UpdateEvents mocks base method. -func (m *MockDevfileData) UpdateEvents(postStart, postStop, preStart, preStop []string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "UpdateEvents", postStart, postStop, preStart, preStop) -} - -// UpdateEvents indicates an expected call of UpdateEvents. -func (mr *MockDevfileDataMockRecorder) UpdateEvents(postStart, postStop, preStart, preStop interface{}) *gomock.Call { +// SetPorts indicates an expected call of SetPorts +func (mr *MockDevfileDataMockRecorder) SetPorts(containerPortsMap interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateEvents", reflect.TypeOf((*MockDevfileData)(nil).UpdateEvents), postStart, postStop, preStart, preStop) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPorts", reflect.TypeOf((*MockDevfileData)(nil).SetPorts), containerPortsMap) } -// UpdateProject mocks base method. -func (m *MockDevfileData) UpdateProject(project v1alpha2.Project) error { +// AddEnvVars mocks base method +func (m *MockDevfileData) AddEnvVars(containerEnvMap map[string][]v1alpha2.EnvVar) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateProject", project) + ret := m.ctrl.Call(m, "AddEnvVars", containerEnvMap) ret0, _ := ret[0].(error) return ret0 } -// UpdateProject indicates an expected call of UpdateProject. -func (mr *MockDevfileDataMockRecorder) UpdateProject(project interface{}) *gomock.Call { +// AddEnvVars indicates an expected call of AddEnvVars +func (mr *MockDevfileDataMockRecorder) AddEnvVars(containerEnvMap interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProject", reflect.TypeOf((*MockDevfileData)(nil).UpdateProject), project) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddEnvVars", reflect.TypeOf((*MockDevfileData)(nil).AddEnvVars), containerEnvMap) } -// UpdateStarterProject mocks base method. -func (m *MockDevfileData) UpdateStarterProject(project v1alpha2.StarterProject) error { +// RemovePorts mocks base method +func (m *MockDevfileData) RemovePorts(containerPortsMap map[string][]string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateStarterProject", project) + ret := m.ctrl.Call(m, "RemovePorts", containerPortsMap) ret0, _ := ret[0].(error) return ret0 } -// UpdateStarterProject indicates an expected call of UpdateStarterProject. -func (mr *MockDevfileDataMockRecorder) UpdateStarterProject(project interface{}) *gomock.Call { +// RemovePorts indicates an expected call of RemovePorts +func (mr *MockDevfileDataMockRecorder) RemovePorts(containerPortsMap interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStarterProject", reflect.TypeOf((*MockDevfileData)(nil).UpdateStarterProject), project) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemovePorts", reflect.TypeOf((*MockDevfileData)(nil).RemovePorts), containerPortsMap) } diff --git a/pkg/devfile/parser/data/v2/containers.go b/pkg/devfile/parser/data/v2/containers.go new file mode 100644 index 00000000..cc87ece4 --- /dev/null +++ b/pkg/devfile/parser/data/v2/containers.go @@ -0,0 +1,265 @@ +package v2 + +import ( + "fmt" + "strconv" + "strings" + + v1alpha2 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" + corev1 "k8s.io/api/core/v1" +) + +func (d *DevfileV2) AddEnvVars(containerEnvMap map[string][]v1alpha2.EnvVar) error { + components, err := d.GetComponents(common.DevfileOptions{}) + if err != nil { + return err + } + for _, component := range components { + if component.Container != nil { + component.Container.Env = merge(component.Container.Env, containerEnvMap[component.Name]) + d.UpdateComponent(component) + } + } + return nil +} + +func (d *DevfileV2) RemoveEnvVars(containerEnvMap map[string][]string) error { + components, err := d.GetComponents(common.DevfileOptions{}) + if err != nil { + return err + } + for _, component := range components { + if component.Container != nil { + component.Container.Env, err = removeEnvVarsFromList(component.Container.Env, containerEnvMap[component.Name]) + if err != nil { + return err + } + d.UpdateComponent(component) + } + } + return nil +} +func (d *DevfileV2) SetPorts(containerPortsMap map[string][]string) error { + components, err := d.GetComponents(common.DevfileOptions{}) + if err != nil { + return err + } + for _, component := range components { + endpoints, err := portsToEndpoints(containerPortsMap[component.Name]...) + if err != nil { + return err + } + if component.Container != nil { + component.Container.Endpoints = addEndpoints(component.Container.Endpoints, endpoints) + d.UpdateComponent(component) + } + } + + return nil +} + +func (d *DevfileV2) RemovePorts(containerPortsMap map[string][]string) error { + components, err := d.GetComponents(common.DevfileOptions{}) + if err != nil { + return err + } + for _, component := range components { + if component.Container != nil { + component.Container.Endpoints, err = removePortsFromList(component.Container.Endpoints, containerPortsMap[component.Name]) + if err != nil { + return err + } + d.UpdateComponent(component) + } + } + + return nil +} + +// removeEnvVarsFromList removes the env variables based on the keys provided +// and returns a new EnvVarList +func removeEnvVarsFromList(envVarList []v1alpha2.EnvVar, keys []string) ([]v1alpha2.EnvVar, error) { + // convert the array of envVarList to a map such that it can easily search for env var(s) + // to remove from the component + envVarListMap := map[string]bool{} + for _, env := range envVarList { + if !envVarListMap[env.Name] { + envVarListMap[env.Name] = true + } + } + + // convert the array of keys to a map so that it can do a fast search for environment variable(s) + // to remove from the component + envVarToBeRemoved := map[string]bool{} + // now check if the environment variable(s) requested for removal exists in + // the env vars currently set in the component + // if an env var requested for removal is not currently set, then raise an error + // else add the env var to the envVarToBeRemoved map + for _, key := range keys { + if !envVarListMap[key] { + return envVarList, fmt.Errorf("unable to find environment variable %s in the component", key) + } + envVarToBeRemoved[key] = true + } + + // finally, let's remove the environment variables(s) requested by the user + newEnvVarList := []v1alpha2.EnvVar{} + for _, envVar := range envVarList { + // if the env is in the keys(env var(s) to be removed), we skip it + if envVarToBeRemoved[envVar.Name] { + continue + } + newEnvVarList = append(newEnvVarList, envVar) + } + return newEnvVarList, nil +} + +// removePortsFromList removes the ports from a given Endpoint list based on the provided port numbers +// and returns a new list of Endpoint +func removePortsFromList(endpoints []v1alpha2.Endpoint, ports []string) ([]v1alpha2.Endpoint, error) { + // convert the array of Endpoint to a map such that it can easily search for port(s) + // to remove from the component + portInEndpoint := map[string]bool{} + for _, ep := range endpoints { + port := strconv.Itoa(ep.TargetPort) + if !portInEndpoint[port] { + portInEndpoint[port] = true + } + } + + // convert the array of ports to a map so that it can do a fast search for port(s) + // to remove from the component + portsToBeRemoved := map[string]bool{} + + // now check if the port(s) requested for removal exists in + // the ports currently present in the component; + // if a port requested for removal is not currently present, then raise an error + // else add the port to the portsToBeRemoved map + for _, port := range ports { + if !portInEndpoint[port] { + return endpoints, fmt.Errorf("unable to find port %q in the component", port) + } + portsToBeRemoved[port] = true + } + + // finally, let's remove the port(s) requested by the user + newEndpointsList := []v1alpha2.Endpoint{} + for _, ep := range endpoints { + // if the port is in the port(s)(to be removed), we skip it + if portsToBeRemoved[strconv.Itoa(ep.TargetPort)] { + continue + } + newEndpointsList = append(newEndpointsList, ep) + } + return newEndpointsList, nil +} + +// merge merges the other EnvVarlist with keeping last value for duplicate EnvVars +// and returns a new EnvVarList +func merge(original []v1alpha2.EnvVar, other []v1alpha2.EnvVar) []v1alpha2.EnvVar { + + var dedupNewEvl []v1alpha2.EnvVar + newEvl := append(original, other...) + uniqueMap := make(map[string]string) + // last value will be kept in case of duplicate env vars + for _, envVar := range newEvl { + uniqueMap[envVar.Name] = envVar.Value + } + + for key, value := range uniqueMap { + dedupNewEvl = append(dedupNewEvl, v1alpha2.EnvVar{ + Name: key, + Value: value, + }) + } + + return dedupNewEvl + +} + +func portsToEndpoints(ports ...string) ([]v1alpha2.Endpoint, error) { + var endpoints []v1alpha2.Endpoint + conPorts, err := getContainerPortsFromStrings(ports) + if err != nil { + return nil, err + } + for _, port := range conPorts { + + endpoint := v1alpha2.Endpoint{ + Name: fmt.Sprintf("port-%d-%s", port.ContainerPort, strings.ToLower(string(port.Protocol))), + TargetPort: int(port.ContainerPort), + Protocol: v1alpha2.EndpointProtocol(strings.ToLower(string(port.Protocol))), + } + endpoints = append(endpoints, endpoint) + } + return endpoints, nil + +} + +func addEndpoints(current []v1alpha2.Endpoint, other []v1alpha2.Endpoint) []v1alpha2.Endpoint { + newList := make([]v1alpha2.Endpoint, len(current)) + copy(newList, current) + for _, ep := range other { + present := false + + for _, presentep := range newList { + + protocol := presentep.Protocol + if protocol == "" { + // endpoint protocol default value is http + protocol = "http" + } + // if the target port and protocol match, we add a case where the protocol is not provided and hence we assume that to be "tcp" + if presentep.TargetPort == ep.TargetPort && (ep.Protocol == protocol) { + present = true + break + } + } + if !present { + newList = append(newList, ep) + } + } + + return newList +} + +// getContainerPortsFromStrings generates ContainerPort values from the array of string port values +// ports is the array containing the string port values +func getContainerPortsFromStrings(ports []string) ([]corev1.ContainerPort, error) { + var containerPorts []corev1.ContainerPort + for _, port := range ports { + splits := strings.Split(port, "/") + if len(splits) < 1 || len(splits) > 2 { + return nil, fmt.Errorf("unable to parse the port string %s", port) + } + + portNumberI64, err := strconv.ParseInt(splits[0], 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid port number %s", splits[0]) + } + portNumber := int32(portNumberI64) + + var portProto corev1.Protocol + if len(splits) == 2 { + switch strings.ToUpper(splits[1]) { + case "TCP": + portProto = corev1.ProtocolTCP + case "UDP": + portProto = corev1.ProtocolUDP + default: + return nil, fmt.Errorf("invalid port protocol %s", splits[1]) + } + } else { + portProto = corev1.ProtocolTCP + } + + port := corev1.ContainerPort{ + Name: fmt.Sprintf("%d-%s", portNumber, strings.ToLower(string(portProto))), + ContainerPort: portNumber, + Protocol: portProto, + } + containerPorts = append(containerPorts, port) + } + return containerPorts, nil +} diff --git a/pkg/devfile/parser/data/v2/containers_test.go b/pkg/devfile/parser/data/v2/containers_test.go new file mode 100644 index 00000000..5f79e23b --- /dev/null +++ b/pkg/devfile/parser/data/v2/containers_test.go @@ -0,0 +1,662 @@ +package v2 + +import ( + "reflect" + "testing" + + "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" + "github.com/kylelemons/godebug/pretty" +) + +func TestAddEnvVars(t *testing.T) { + + tests := []struct { + name string + listToAdd map[string][]v1alpha2.EnvVar + currentDevfile *DevfileV2 + wantDevFile *DevfileV2 + }{ + { + name: "add env vars", + listToAdd: map[string][]v1alpha2.EnvVar{ + "loadbalancer": { + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + currentDevfile: testDevfileData(), + wantDevFile: &DevfileV2{ + Devfile: v1alpha2.Devfile{ + DevWorkspaceTemplateSpec: v1alpha2.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{ + Commands: []v1alpha2.Command{ + { + Id: "devbuild", + CommandUnion: v1alpha2.CommandUnion{ + Exec: &v1alpha2.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1alpha2.Component{ + { + Name: "runtime", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nodejs-12", + Env: []v1alpha2.EnvVar{ + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + Endpoints: []v1alpha2.Endpoint{ + { + Name: "port-3030", + TargetPort: 3030, + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nginx", + Env: []v1alpha2.EnvVar{ + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + }, + }, + }, + }, + Events: &v1alpha2.Events{ + DevWorkspaceEvents: v1alpha2.DevWorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1alpha2.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + StarterProjects: []v1alpha2.StarterProject{ + { + SubDir: "/projects", + Name: "starter-project-2", + }, + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.currentDevfile.AddEnvVars(tt.listToAdd) + + if err != nil { + t.Errorf("TestAddAndRemoveEnvVars() unexpected error while adding env vars %+v", err.Error()) + } + + if !reflect.DeepEqual(tt.currentDevfile, tt.wantDevFile) { + t.Errorf("TestAddAndRemoveEnvVars() error: wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile, tt.wantDevFile)) + } + + }) + } + +} + +func TestRemoveEnvVars(t *testing.T) { + + tests := []struct { + name string + listToRemove map[string][]string + currentDevfile *DevfileV2 + wantDevFile *DevfileV2 + wantRemoveErr bool + }{ + { + name: "remove env vars", + listToRemove: map[string][]string{ + "runtime": { + "DATABASE_PASSWORD", + }, + }, + currentDevfile: testDevfileData(), + wantDevFile: &DevfileV2{ + Devfile: v1alpha2.Devfile{ + DevWorkspaceTemplateSpec: v1alpha2.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{ + Commands: []v1alpha2.Command{ + { + Id: "devbuild", + CommandUnion: v1alpha2.CommandUnion{ + Exec: &v1alpha2.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1alpha2.Component{ + { + Name: "runtime", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nodejs-12", + Env: []v1alpha2.EnvVar{}, + }, + Endpoints: []v1alpha2.Endpoint{ + { + Name: "port-3030", + TargetPort: 3030, + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nginx", + Env: []v1alpha2.EnvVar{}, + }, + }, + }, + }, + }, + Events: &v1alpha2.Events{ + DevWorkspaceEvents: v1alpha2.DevWorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1alpha2.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + StarterProjects: []v1alpha2.StarterProject{ + { + SubDir: "/projects", + Name: "starter-project-2", + }, + }, + }, + }, + }, + }, + }, + { + name: "remove non-existent env vars", + listToRemove: map[string][]string{ + "runtime": { + "NON_EXISTENT_KEY", + }, + }, + currentDevfile: testDevfileData(), + wantDevFile: &DevfileV2{ + Devfile: v1alpha2.Devfile{ + DevWorkspaceTemplateSpec: v1alpha2.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{ + Commands: []v1alpha2.Command{ + { + Id: "devbuild", + CommandUnion: v1alpha2.CommandUnion{ + Exec: &v1alpha2.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1alpha2.Component{ + { + Name: "runtime", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nodejs-12", + Env: []v1alpha2.EnvVar{ + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + Endpoints: []v1alpha2.Endpoint{ + { + Name: "port-3030", + TargetPort: 3030, + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nginx", + }, + }, + }, + }, + }, + Events: &v1alpha2.Events{ + DevWorkspaceEvents: v1alpha2.DevWorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1alpha2.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + StarterProjects: []v1alpha2.StarterProject{ + { + SubDir: "/projects", + Name: "starter-project-2", + }, + }, + }, + }, + }, + }, + wantRemoveErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.currentDevfile.RemoveEnvVars(tt.listToRemove) + + if (err != nil) != tt.wantRemoveErr { + t.Errorf("TestAddAndRemoveEnvVars() unexpected error while removing env vars %+v", err.Error()) + } + + if !reflect.DeepEqual(tt.currentDevfile, tt.wantDevFile) { + t.Errorf("TestAddAndRemoveEnvVars() error: wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile, tt.wantDevFile)) + } + + }) + } + +} + +func TestSetPorts(t *testing.T) { + + tests := []struct { + name string + portToSet map[string][]string + currentDevfile *DevfileV2 + wantDevFile *DevfileV2 + }{ + { + name: "set ports", + portToSet: map[string][]string{"runtime": {"9000"}, "loadbalancer": {"8000"}}, + currentDevfile: testDevfileData(), + wantDevFile: &DevfileV2{ + Devfile: v1alpha2.Devfile{ + DevWorkspaceTemplateSpec: v1alpha2.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{ + Commands: []v1alpha2.Command{ + { + Id: "devbuild", + CommandUnion: v1alpha2.CommandUnion{ + Exec: &v1alpha2.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1alpha2.Component{ + { + Name: "runtime", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nodejs-12", + Env: []v1alpha2.EnvVar{ + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + Endpoints: []v1alpha2.Endpoint{ + { + Name: "port-3030", + TargetPort: 3030, + }, + { + Name: "port-9000-tcp", + TargetPort: 9000, + Protocol: "tcp", + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nginx", + }, + Endpoints: []v1alpha2.Endpoint{ + { + Name: "port-8000-tcp", + TargetPort: 8000, + Protocol: "tcp", + }, + }, + }, + }, + }, + }, + Events: &v1alpha2.Events{ + DevWorkspaceEvents: v1alpha2.DevWorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1alpha2.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + StarterProjects: []v1alpha2.StarterProject{ + { + SubDir: "/projects", + Name: "starter-project-2", + }, + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.currentDevfile.SetPorts(tt.portToSet) + + if err != nil { + t.Errorf("TestSetAndRemovePorts() unexpected error while adding ports %+v", err.Error()) + } + + if !reflect.DeepEqual(tt.currentDevfile, tt.wantDevFile) { + t.Errorf("TestSetAndRemovePorts() error: wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile, tt.wantDevFile)) + } + }) + } + +} + +func TestRemovePorts(t *testing.T) { + + tests := []struct { + name string + portToRemove map[string][]string + currentDevfile *DevfileV2 + wantDevFile *DevfileV2 + wantRemoveErr bool + }{ + { + name: "remove ports", + portToRemove: map[string][]string{"runtime": {"3030"}}, + currentDevfile: testDevfileData(), + wantDevFile: &DevfileV2{ + Devfile: v1alpha2.Devfile{ + DevWorkspaceTemplateSpec: v1alpha2.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{ + Commands: []v1alpha2.Command{ + { + Id: "devbuild", + CommandUnion: v1alpha2.CommandUnion{ + Exec: &v1alpha2.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1alpha2.Component{ + { + Name: "runtime", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nodejs-12", + Env: []v1alpha2.EnvVar{ + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + Endpoints: []v1alpha2.Endpoint{}, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nginx", + }, + Endpoints: []v1alpha2.Endpoint{}, + }, + }, + }, + }, + Events: &v1alpha2.Events{ + DevWorkspaceEvents: v1alpha2.DevWorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1alpha2.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + StarterProjects: []v1alpha2.StarterProject{ + { + SubDir: "/projects", + Name: "starter-project-2", + }, + }, + }, + }, + }, + }, + }, + { + name: "remove non-existent ports", + portToRemove: map[string][]string{"runtime": {"3050"}}, + currentDevfile: testDevfileData(), + wantDevFile: &DevfileV2{ + Devfile: v1alpha2.Devfile{ + DevWorkspaceTemplateSpec: v1alpha2.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{ + Commands: []v1alpha2.Command{ + { + Id: "devbuild", + CommandUnion: v1alpha2.CommandUnion{ + Exec: &v1alpha2.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1alpha2.Component{ + { + Name: "runtime", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nodejs-12", + Env: []v1alpha2.EnvVar{ + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + Endpoints: []v1alpha2.Endpoint{ + { + Name: "port-3030", + TargetPort: 3030, + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nginx", + }, + }, + }, + }, + }, + Events: &v1alpha2.Events{ + DevWorkspaceEvents: v1alpha2.DevWorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1alpha2.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + StarterProjects: []v1alpha2.StarterProject{ + { + SubDir: "/projects", + Name: "starter-project-2", + }, + }, + }, + }, + }, + }, + wantRemoveErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.currentDevfile.RemovePorts(tt.portToRemove) + + if (err != nil) != tt.wantRemoveErr { + t.Errorf("TestSetAndRemovePorts() unexpected error while removing ports %+v", err.Error()) + } + + if !reflect.DeepEqual(tt.currentDevfile, tt.wantDevFile) { + t.Errorf("TestSetAndRemovePorts() error: wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile, tt.wantDevFile)) + } + }) + } + +} + +func testDevfileData() *DevfileV2 { + return &DevfileV2{ + Devfile: v1alpha2.Devfile{ + DevWorkspaceTemplateSpec: v1alpha2.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{ + Commands: []v1alpha2.Command{ + { + Id: "devbuild", + CommandUnion: v1alpha2.CommandUnion{ + Exec: &v1alpha2.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1alpha2.Component{ + { + Name: "runtime", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nodejs-12", + Env: []v1alpha2.EnvVar{ + { + Name: "DATABASE_PASSWORD", + Value: "苦痛", + }, + }, + }, + Endpoints: []v1alpha2.Endpoint{ + { + Name: "port-3030", + TargetPort: 3030, + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1alpha2.ComponentUnion{ + Container: &v1alpha2.ContainerComponent{ + Container: v1alpha2.Container{ + Image: "quay.io/nginx", + }, + }, + }, + }, + }, + Events: &v1alpha2.Events{ + DevWorkspaceEvents: v1alpha2.DevWorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1alpha2.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + StarterProjects: []v1alpha2.StarterProject{ + { + SubDir: "/projects", + Name: "starter-project-2", + }, + }, + }, + }, + }, + } +}