| 162 | } |
| 163 | |
| 164 | func collectWorkspaceEnv(flattenedDW *dw.DevWorkspaceTemplateSpec) ([]corev1.EnvVar, error) { |
| 165 | // Use a map to store all workspace env vars to avoid duplicates |
| 166 | workspaceEnvMap := map[string]string{} |
| 167 | |
| 168 | // Bookkeeping map so that we can format error messages in case of conflict |
| 169 | envVarToComponent := map[string]string{} |
| 170 | |
| 171 | if flattenedDW.Attributes.Exists(constants.WorkspaceEnvAttribute) { |
| 172 | var dwEnv []dw.EnvVar |
| 173 | err := flattenedDW.Attributes.GetInto(constants.WorkspaceEnvAttribute, &dwEnv) |
| 174 | if err != nil { |
| 175 | return nil, fmt.Errorf("failed to read attribute %s in DevWorkspace attributes: %w", constants.WorkspaceEnvAttribute, err) |
| 176 | } |
| 177 | for _, envVar := range dwEnv { |
| 178 | if existingVal, exists := workspaceEnvMap[envVar.Name]; exists && existingVal != envVar.Value { |
| 179 | return nil, fmt.Errorf("conflicting definition of environment variable %s in DevWorkspace attributes", |
| 180 | envVar.Name) |
| 181 | } |
| 182 | workspaceEnvMap[envVar.Name] = envVar.Value |
| 183 | envVarToComponent[envVar.Name] = "DevWorkspace attributes" |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | for _, component := range flattenedDW.Components { |
| 188 | if !component.Attributes.Exists(constants.WorkspaceEnvAttribute) { |
| 189 | continue |
| 190 | } |
| 191 | |
| 192 | var componentEnv []dw.EnvVar |
| 193 | err := component.Attributes.GetInto(constants.WorkspaceEnvAttribute, &componentEnv) |
| 194 | if err != nil { |
| 195 | return nil, fmt.Errorf("failed to read attribute %s on %s: %w", constants.WorkspaceEnvAttribute, getSourceForComponent(component), err) |
| 196 | } |
| 197 | |
| 198 | for _, envVar := range componentEnv { |
| 199 | if existingVal, exists := workspaceEnvMap[envVar.Name]; exists && existingVal != envVar.Value { |
| 200 | return nil, fmt.Errorf("conflicting definition of environment variable %s in %s and %s", |
| 201 | envVar.Name, envVarToComponent[envVar.Name], getSourceForComponent(component)) |
| 202 | } |
| 203 | workspaceEnvMap[envVar.Name] = envVar.Value |
| 204 | envVarToComponent[envVar.Name] = getSourceForComponent(component) |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | var workspaceEnv []corev1.EnvVar |
| 209 | for name, value := range workspaceEnvMap { |
| 210 | workspaceEnv = append(workspaceEnv, corev1.EnvVar{Name: name, Value: value}) |
| 211 | } |
| 212 | return workspaceEnv, nil |
| 213 | } |
| 214 | |
| 215 | // getSourceForComponent returns the 'original' name for a component in a flattened DevWorkspace. Given a component, it |
| 216 | // returns the name of the plugin component that imported it if the component came via a plugin, and the actual |