Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to define workspace deployment labels #18100

Merged
merged 2 commits into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import static java.lang.String.format;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toMap;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putAnnotations;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabels;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.shouldCreateInCheNamespace;
import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.CHECK_SERVERS;
import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.WAIT_MACHINES_START;
Expand Down Expand Up @@ -782,7 +784,8 @@ protected void doStartMachine(ServerResolver serverResolver) throws Infrastructu
injectables.add(new PodData(toCreate));
Deployment deployment = podMerger.merge(injectables);
deployment.getMetadata().setName(toCreate.getMetadata().getName());

putAnnotations(deployment.getMetadata(), toCreate.getMetadata().getAnnotations());
putLabels(deployment.getMetadata(), toCreate.getMetadata().getLabels());
createdPod = namespace.deployments().deploy(deployment);
} catch (ValidationException e) {
throw new InfrastructureException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,14 @@ public final class Warnings {
public static final String NOT_ABLE_TO_PROVISION_SSH_KEYS_MESSAGE =
"Not able to provision SSH Keys. Message: '%s'";

public static final int NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT = 4200;
public static final String NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_MESSAGE =
"Not able to find workspace attributes for %s. Reason %s";

public static final int NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_LABELS_OR_ANNOTATIONS = 4250;
public static final String
NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_LABELS_OR_ANNOTATIONS_MESSAGE =
"Not able to provision workspace %s deployment labels or annotations because of invalid configuration. Reason: '%s'";

private Warnings() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -437,4 +437,29 @@ public String toString() {
return "PodData{" + "podSpec=" + podSpec + ", podMeta=" + podMeta + ", role=" + role + '}';
}
}

@Override
public String toString() {
return "KubernetesEnvironment{"
+ "pods="
+ pods
+ ", deployments="
+ deployments
+ ", podData="
+ podData
+ ", services="
+ services
+ ", ingresses="
+ ingresses
+ ", persistentVolumeClaims="
+ persistentVolumeClaims
+ ", secrets="
+ secrets
+ ", configMaps="
+ configMaps
+ ", injectablePods="
+ injectablePods
+ "} "
+ super.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.provision;

import static java.lang.String.format;
import static org.eclipse.che.workspace.infrastructure.kubernetes.Warnings.NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT;
import static org.eclipse.che.workspace.infrastructure.kubernetes.Warnings.NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_LABELS_OR_ANNOTATIONS;
import static org.eclipse.che.workspace.infrastructure.kubernetes.Warnings.NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_LABELS_OR_ANNOTATIONS_MESSAGE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.Warnings.NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_MESSAGE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putAnnotations;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabels;

import com.google.common.base.Splitter;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import java.util.Map;
import javax.inject.Inject;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.workspace.Workspace;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.server.model.impl.WarningImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Class that is provisioning deployment labels and annotations that are configured in workspace
* attributes.
*/
public class DeploymentMetadataProvisioner
implements ConfigurationProvisioner<KubernetesEnvironment> {

public static final String WS_DEPLOYMENT_LABELS_ATTR_NAME = "workspaceDeploymentLabels";
public static final String WS_DEPLOYMENT_ANNOTATIONS_ATTR_NAME = "workspaceDeploymentAnnotations";
private static final Logger LOG = LoggerFactory.getLogger(DeploymentMetadataProvisioner.class);

private final WorkspaceManager workspaceManager;
private final Splitter.MapSplitter splitter = Splitter.on(",").withKeyValueSeparator("=");

@Inject
public DeploymentMetadataProvisioner(WorkspaceManager workspaceManager) {
this.workspaceManager = workspaceManager;
}

@Override
public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity)
throws InfrastructureException {
try {
Workspace wsg = workspaceManager.getWorkspace(identity.getWorkspaceId());
for (Deployment d : k8sEnv.getDeploymentsCopy().values()) {
Map<String, String> workspaceAttributes = wsg.getAttributes();
if (workspaceAttributes.containsKey(WS_DEPLOYMENT_LABELS_ATTR_NAME)) {
putLabels(
d.getMetadata(),
splitter.split(workspaceAttributes.get(WS_DEPLOYMENT_LABELS_ATTR_NAME)));
}
if (workspaceAttributes.containsKey(WS_DEPLOYMENT_ANNOTATIONS_ATTR_NAME)) {
putAnnotations(
d.getMetadata(),
splitter.split(workspaceAttributes.get(WS_DEPLOYMENT_ANNOTATIONS_ATTR_NAME)));
}
}
} catch (NotFoundException | ServerException e) {
String message =
format(
NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_MESSAGE,
identity.getWorkspaceId(),
e.getMessage());
LOG.warn(message);
k8sEnv.addWarning(new WarningImpl(NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT, message));
} catch (IllegalArgumentException e) {
String message =
format(
NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_LABELS_OR_ANNOTATIONS_MESSAGE,
identity.getWorkspaceId(),
e.getMessage());
LOG.warn(message);
k8sEnv.addWarning(
new WarningImpl(
NOT_ABLE_TO_PROVISION_WORKSPACE_DEPLOYMENT_LABELS_OR_ANNOTATIONS, message));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import static org.eclipse.che.dto.server.DtoFactory.newDto;
import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putAnnotations;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabels;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostExternalServiceExposureStrategy.MULTI_HOST_STRATEGY;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
Expand Down Expand Up @@ -1070,6 +1072,49 @@ public void testMultipleMachinesRequiringSamePodInjectionResultInOnePodInjected(
new HashSet<>(asList(CONTAINER_NAME_1, CONTAINER_NAME_2, "injectedContainer")));
}

@Test
public void testDeploymentLabelsAndAnnotations() throws Exception {
// given
Map<String, Pod> injectedPods =
ImmutableMap.of("injected", mockPod(singletonList(mockContainer("injectedContainer"))));

doReturn(ImmutableMap.of(M1_NAME, injectedPods)).when(k8sEnv).getInjectablePodsCopy();

doReturn(emptyMap()).when(k8sEnv).getPodsCopy();
Deployment deployment = mockDeployment(singletonList(mockContainer(CONTAINER_NAME_1)));

putLabels(deployment.getMetadata(), ImmutableMap.of("k1", "v2", "k3", "v4"));
putAnnotations(deployment.getMetadata(), ImmutableMap.of("ak1", "av2", "ak3", "av4"));
doReturn(ImmutableMap.of(WORKSPACE_POD_NAME, deployment)).when(k8sEnv).getDeploymentsCopy();

doReturn(
ImmutableMap.of(
M1_NAME,
mock(InternalMachineConfig.class),
WORKSPACE_POD_NAME + "/injectedContainer",
mock(InternalMachineConfig.class)))
.when(k8sEnv)
.getMachines();

// when
internalRuntime.start(emptyMap());

// then
ArgumentCaptor<Deployment> deploymentCaptor = ArgumentCaptor.forClass(Deployment.class);

verify(deployments).deploy(deploymentCaptor.capture());
assertTrue(deployment.getMetadata().getLabels().containsKey("k1"));
assertTrue(deployment.getMetadata().getLabels().containsKey("k3"));
assertEquals(
deployment.getMetadata().getLabels(),
deploymentCaptor.getValue().getMetadata().getLabels());
assertTrue(deployment.getMetadata().getAnnotations().containsKey("ak1"));
assertTrue(deployment.getMetadata().getAnnotations().containsKey("ak3"));
assertEquals(
deployment.getMetadata().getAnnotations(),
deploymentCaptor.getValue().getMetadata().getAnnotations());
}

@Test
public void testInjectablePodsMergedIntoRuntimeDeployments() throws Exception {
// given
Expand Down
Loading