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

capacity providers #211

Merged
merged 7 commits into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ TaskRole:
Resource: "*"
- Action:
- "ecs:ListContainerInstances"
- "ecs:DescribeClusters"
Effect: Allow
Resource:
- !Sub "arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/<clusterName>"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,8 @@ TaskDefinition registerTemplate(final String cloudName, final ECSTaskTemplate te

if (template.isFargate()) {
request
.withRequiresCompatibilities(template.getLaunchType())
.withNetworkMode("awsvpc")
.withRequiresCompatibilities(LaunchType.FARGATE.toString())
.withNetworkMode(NetworkMode.Awsvpc.toString())
.withMemory(String.valueOf(template.getMemoryConstraint()))
.withCpu(String.valueOf(template.getCpu()));
}
Expand Down Expand Up @@ -406,7 +406,6 @@ RunTaskResult runEcsTask(final ECSSlave agent, final ECSTaskTemplate template, S

RunTaskRequest req = new RunTaskRequest()
.withTaskDefinition(taskDefinition.getTaskDefinitionArn())
.withLaunchType(LaunchType.fromValue(template.getLaunchType()))
.withOverrides(new TaskOverride()
.withContainerOverrides(new ContainerOverride()
.withName(agentContainerName)
Expand All @@ -415,8 +414,13 @@ RunTaskResult runEcsTask(final ECSSlave agent, final ECSTaskTemplate template, S
.withEnvironment(envNodeSecret)))
.withPlacementStrategy(template.getPlacementStrategyEntries())
.withCluster(clusterArn);

if (template.getLaunchType() != null && template.getLaunchType().equals("FARGATE")) {
if ( ! template.getDefaultCapacityProvider() && template.getCapacityProviderStrategies() == null ) {
req.withLaunchType(LaunchType.fromValue(template.getLaunchType()));
}
if ( ! template.getDefaultCapacityProvider() && template.getCapacityProviderStrategies() != null ) {
req.withCapacityProviderStrategy(template.getCapacityProviderStrategyEntries());
}
if (template.isFargate()) {
req.withPlatformVersion(template.getPlatformVersion());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@

package com.cloudbees.jenkins.plugins.amazonecs;

import com.amazonaws.services.ecs.AmazonECS;
import com.amazonaws.services.ecs.model.AwsVpcConfiguration;
import com.amazonaws.services.ecs.model.ContainerDefinition;
import com.amazonaws.services.ecs.model.HostEntry;
import com.amazonaws.services.ecs.model.HostVolumeProperties;
import com.amazonaws.services.ecs.model.KeyValuePair;
import com.amazonaws.services.ecs.model.LaunchType;
import com.amazonaws.services.ecs.model.CapacityProviderStrategyItem;
import com.amazonaws.services.ecs.model.LinuxParameters;
import com.amazonaws.services.ecs.model.MountPoint;
import com.amazonaws.services.ecs.model.NetworkMode;
Expand All @@ -40,8 +42,12 @@
import com.amazonaws.services.ecs.model.RegisterTaskDefinitionRequest;
import com.amazonaws.services.ecs.model.RepositoryCredentials;
import com.amazonaws.services.ecs.model.Volume;
import com.amazonaws.services.ecs.model.DescribeClustersRequest;
import com.amazonaws.services.ecs.model.DescribeClustersResult;
import com.amazonaws.services.ecs.model.Cluster;
import static com.google.common.base.Strings.isNullOrEmpty;
import hudson.Extension;
import hudson.RelativePath;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.model.Label;
Expand Down Expand Up @@ -71,6 +77,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.Collections;

/**
* @author <a href="mailto:[email protected]">Nicolas De Loof</a>
Expand Down Expand Up @@ -238,6 +245,12 @@ public int getMemoryConstraint() {
*/
private final String launchType;

/**
* Use default capacity provider will omit launch types and capacity strategies
*
*/
private boolean defaultCapacityProvider;

/**
* Task network mode
*/
Expand Down Expand Up @@ -269,7 +282,7 @@ public int getMemoryConstraint() {
private List<ExtraHostEntry> extraHosts;
private List<PortMappingEntry> portMappings;
private List<PlacementStrategyEntry> placementStrategies;

private List<CapacityProviderStrategyEntry> capacityProviderStrategies;


/**
Expand Down Expand Up @@ -301,7 +314,9 @@ public ECSTaskTemplate(String templateName,
@Nullable String dynamicTaskDefinitionOverride,
String image,
@Nullable final String repositoryCredentials,
String launchType,
@Nullable String launchType,
boolean defaultCapacityProvider,
@Nullable List<CapacityProviderStrategyEntry> capacityProviderStrategies,
String networkMode,
@Nullable String remoteFSRoot,
boolean uniqueRemoteFSRoot,
Expand Down Expand Up @@ -349,6 +364,8 @@ public ECSTaskTemplate(String templateName,
this.memoryReservation = memoryReservation;
this.cpu = cpu;
this.launchType = launchType;
this.defaultCapacityProvider = defaultCapacityProvider;
this.capacityProviderStrategies = capacityProviderStrategies;
this.networkMode = networkMode;
this.subnets = subnets;
this.securityGroups = securityGroups;
Expand Down Expand Up @@ -425,6 +442,15 @@ public void setDnsSearchDomains(String dnsSearchDomains) {
}

public boolean isFargate() {
if (!this.defaultCapacityProvider && this.capacityProviderStrategies != null && ! this.capacityProviderStrategies.isEmpty()) {
for (CapacityProviderStrategyEntry capacityProviderStrategy : this.capacityProviderStrategies) {
String provider = capacityProviderStrategy.provider;
if (provider.contains(LaunchType.FARGATE.toString())) {
return true;
}
}
return false;
}
return StringUtils.trimToNull(this.launchType) != null && launchType.equals(LaunchType.FARGATE.toString());
}

Expand Down Expand Up @@ -489,6 +515,10 @@ public boolean getAssignPublicIp() {
return assignPublicIp;
}

public boolean getDefaultCapacityProvider() {
return defaultCapacityProvider;
}

public String getDnsSearchDomains() {
return dnsSearchDomains;
}
Expand Down Expand Up @@ -613,6 +643,10 @@ public List<PlacementStrategyEntry> getPlacementStrategies() {
return placementStrategies;
}

public List<CapacityProviderStrategyEntry> getCapacityProviderStrategies() {
return capacityProviderStrategies;
}

/**
* This merge does not take an into consideration the child intentionally setting empty values for parameters like "entrypoint" - in fact
* it's not uncommon to override the entrypoint of a container and set it to blank so you can use your own entrypoint as part of the command.
Expand All @@ -631,6 +665,7 @@ public ECSTaskTemplate merge(ECSTaskTemplate parent) {
String image = isNullOrEmpty(this.image) ? parent.getImage() : this.image;
String repositoryCredentials = isNullOrEmpty(this.repositoryCredentials) ? parent.getRepositoryCredentials() : this.repositoryCredentials;
String launchType = isNullOrEmpty(this.launchType) ? parent.getLaunchType() : this.launchType;
boolean defaultCapacityProvider = this.defaultCapacityProvider ? this.defaultCapacityProvider : parent.getDefaultCapacityProvider();
String networkMode = isNullOrEmpty(this.networkMode) ? parent.getNetworkMode() : this.networkMode;
String remoteFSRoot = isNullOrEmpty(this.remoteFSRoot) ? parent.getRemoteFSRoot() : this.remoteFSRoot;

Expand Down Expand Up @@ -660,6 +695,7 @@ public ECSTaskTemplate merge(ECSTaskTemplate parent) {
List<MountPointEntry> mountPoints = isEmpty(this.mountPoints) ? parent.getMountPoints() : this.mountPoints;
List<PortMappingEntry> portMappings = isEmpty(this.portMappings) ? parent.getPortMappings() : this.portMappings;
List<PlacementStrategyEntry> placementStrategies = isEmpty(this.placementStrategies) ? parent.getPlacementStrategies() : this.placementStrategies;
List<CapacityProviderStrategyEntry> capacityProviderStrategies = isEmpty(this.capacityProviderStrategies) ? parent.getCapacityProviderStrategies() : this.capacityProviderStrategies;

String executionRole = isNullOrEmpty(this.executionRole) ? parent.getExecutionRole() : this.executionRole;
String taskrole = isNullOrEmpty(this.taskrole) ? parent.getTaskrole() : this.taskrole;
Expand All @@ -671,6 +707,8 @@ public ECSTaskTemplate merge(ECSTaskTemplate parent) {
image,
repositoryCredentials,
launchType,
defaultCapacityProvider,
capacityProviderStrategies,
networkMode,
remoteFSRoot,
uniqueRemoteFSRoot,
Expand Down Expand Up @@ -802,6 +840,22 @@ Collection<PlacementStrategy> getPlacementStrategyEntries() {
return placements;
}

Collection<CapacityProviderStrategyItem> getCapacityProviderStrategyEntries() {
if (null == capacityProviderStrategies || capacityProviderStrategies.isEmpty())
return null;
Collection<CapacityProviderStrategyItem> stragies = new ArrayList<CapacityProviderStrategyItem>();
for (CapacityProviderStrategyEntry capacityProviderStrategy : this.capacityProviderStrategies) {
String provider = capacityProviderStrategy.provider;
int base = capacityProviderStrategy.base;
int weight = capacityProviderStrategy.weight;

stragies.add(new CapacityProviderStrategyItem().withCapacityProvider(provider)
.withWeight(weight)
.withBase(base));
}
return stragies;
}

public static class EnvironmentEntry extends AbstractDescribableImpl<EnvironmentEntry> implements Serializable {
private static final long serialVersionUID = 4195862080979262875L;
public String name, value;
Expand Down Expand Up @@ -957,6 +1011,56 @@ public FormValidation doCheckField(@QueryParameter("field") String field, @Query
}
}

public static class CapacityProviderStrategyEntry extends AbstractDescribableImpl<CapacityProviderStrategyEntry> implements Serializable {
//private static final long serialVersionUID = 4195862080979262875L;
public String provider;
public int base, weight;

@DataBoundConstructor
public CapacityProviderStrategyEntry(String provider, int base, int weight) {
this.base = base;
this.weight = weight;
this.provider = provider;
}

@Override
public String toString() {
return "CapacityProviderStrategyEntry{" + provider + "base: " + base + "weight: " + weight + "}";
}

@Extension
public static class DescriptorImpl extends Descriptor<CapacityProviderStrategyEntry> {
public ListBoxModel doFillProviderItems(
@RelativePath("../..") @QueryParameter String credentialsId,
@RelativePath("../..") @QueryParameter String regionName,
@RelativePath("../..") @QueryParameter String cluster
){
ECSService ecsService = new ECSService(credentialsId, regionName);
final AmazonECS client = ecsService.getAmazonECSClient();
final List<Cluster> allClusters = new ArrayList<Cluster>();
DescribeClustersResult result = client.describeClusters(new DescribeClustersRequest().withClusters(cluster));
allClusters.addAll(result.getClusters());
final ListBoxModel options = new ListBoxModel();
for ( Cluster c : allClusters) {
List<String> item = c.getCapacityProviders();
Collections.sort(item);
for (String provider : item) {
options.add(provider);
}
}
return options;
}
@Override
public String getDisplayName() {
return "CapacityProviderStrategyEntry";
}

public FormValidation doCheckField(@QueryParameter("base") int base, @QueryParameter("weight") int weight, @QueryParameter("provider") String provider) throws IOException, ServletException {
return FormValidation.ok();
}
}
}

public Set<LabelAtom> getLabelSet() {
return Label.parse(label);
}
Expand Down Expand Up @@ -1142,6 +1246,12 @@ public boolean equals(Object o) {
if (launchType != null ? !launchType.equals(that.launchType) : that.launchType != null) {
return false;
}
if (defaultCapacityProvider != that.defaultCapacityProvider) {
return false;
}
if (capacityProviderStrategies != null ? !capacityProviderStrategies.equals(that.capacityProviderStrategies) : that.capacityProviderStrategies != null) {
return false;
}
if (networkMode != null ? !networkMode.equals(that.networkMode) : that.networkMode != null) {
return false;
}
Expand Down Expand Up @@ -1192,6 +1302,8 @@ public int hashCode() {
result = 31 * result + (jvmArgs != null ? jvmArgs.hashCode() : 0);
result = 31 * result + (mountPoints != null ? mountPoints.hashCode() : 0);
result = 31 * result + (launchType != null ? launchType.hashCode() : 0);
result = 31 * result + (defaultCapacityProvider ? 1 : 0);
result = 31 * result + (capacityProviderStrategies != null ? capacityProviderStrategies.hashCode() : 0);
result = 31 * result + (networkMode != null ? networkMode.hashCode() : 0);
result = 31 * result + (privileged ? 1 : 0);
result = 31 * result + (uniqueRemoteFSRoot ? 1 : 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.cloudbees.jenkins.plugins.amazonecs.ECSTaskTemplate.MountPointEntry;
import com.cloudbees.jenkins.plugins.amazonecs.ECSTaskTemplate.PortMappingEntry;
import com.cloudbees.jenkins.plugins.amazonecs.ECSTaskTemplate.PlacementStrategyEntry;
import com.cloudbees.jenkins.plugins.amazonecs.ECSTaskTemplate.CapacityProviderStrategyEntry;
import com.google.common.collect.ImmutableSet;
import hudson.model.Run;
import java.util.logging.Level;
Expand All @@ -50,6 +51,7 @@ public class ECSTaskTemplateStep extends Step implements Serializable {
private String repositoryCredentials;
private String image;
private String launchType;
private boolean defaultCapacityProvider;
private String networkMode;
private String remoteFSRoot;
private boolean uniqueRemoteFSRoot;
Expand All @@ -73,6 +75,7 @@ public class ECSTaskTemplateStep extends Step implements Serializable {
private List<MountPointEntry> mountPoints;
private List<PortMappingEntry> portMappings;
private List<PlacementStrategyEntry> placementStrategies;
private List<CapacityProviderStrategyEntry> capacityProviderStrategies;

private List<String> overrides;

Expand Down Expand Up @@ -235,6 +238,15 @@ public boolean getAssignPublicIp() {
return assignPublicIp;
}

@DataBoundSetter
public void setDefaultCapacityProvider(boolean defaultCapacityProvider) {
this.defaultCapacityProvider = defaultCapacityProvider;
}

public boolean getDefaultCapacityProvider() {
return defaultCapacityProvider;
}

@DataBoundSetter
public void setPrivileged(boolean privileged) {
this.privileged = privileged;
Expand Down Expand Up @@ -343,6 +355,16 @@ public void setPlacementStrategies(List<PlacementStrategyEntry> placementStrateg
this.placementStrategies = placementStrategies;
}

public List<CapacityProviderStrategyEntry> getCapacityProviderStrategies() {
return capacityProviderStrategies;
}

@DataBoundSetter
public void setCapacityProviderStrategy(List<CapacityProviderStrategyEntry> capacityProviderStrategies) {
this.capacityProviderStrategies = capacityProviderStrategies;
}


@DataBoundSetter
public void setOverrides(List<String> overrides) {
this.overrides = overrides;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public boolean start() throws Exception {
step.getImage(),
step.getRepositoryCredentials(),
step.getLaunchType(),
step.getDefaultCapacityProvider(),
step.getCapacityProviderStrategies(),
step.getNetworkMode(),
step.getRemoteFSRoot(),
step.getUniqueRemoteFSRoot(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,30 @@
<f:entry name="launchType" title="${%Launch type}" field="launchType">
<f:select />
</f:entry>
<f:entry title="${%Default Capacity Provider}" field="defaultCapacityProvider" description="Use Default Capacity Provider. This will ignore Capacity provider strategy and use launch type value to set require capabilities">
<f:checkbox />
</f:entry>
<f:entry field="capacityProviderStrategies" title="${%Capacity provider strategy}">
<f:repeatable field="capacityProviderStrategies">
<table width="100%">
<f:entry field="base" title="${%Base}">
<f:textbox default="0"/>
</f:entry>
<f:entry field="weight" title="${%Weight}">
<f:textbox default="0"/>
</f:entry>
<f:entry name="provider" title="${%Provider}" field="provider">
<f:select />
</f:entry>

<f:entry>
<div align="right">
<f:repeatableDeleteButton />
</div>
</f:entry>
</table>
</f:repeatable>
</f:entry>
<f:entry name="networkMode" title="${%Network mode}" field="networkMode">
<f:select />
</f:entry>
Expand Down
Loading