Skip to content

Commit cbdce2d

Browse files
committed
Add support to setup csi driver on k8s cluster creation
1 parent 109cc65 commit cbdce2d

File tree

13 files changed

+145
-2
lines changed

13 files changed

+145
-2
lines changed

api/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,5 @@ enum State {
166166
Long getEtcdNodeCount();
167167
Long getCniConfigId();
168168
String getCniConfigDetails();
169+
boolean isCsiEnabled();
169170
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ public class ApiConstants {
196196
public static final String DURATION = "duration";
197197
public static final String ELIGIBLE = "eligible";
198198
public static final String EMAIL = "email";
199+
public static final String ENABLE_CSI = "enablecsi";
199200
public static final String END_ASN = "endasn";
200201
public static final String END_DATE = "enddate";
201202
public static final String END_IP = "endip";

engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,6 @@ SET `sort_key` = CASE
203203
ELSE `sort_key`
204204
END;
205205
-- End: Changes for Guest OS category cleanup
206+
207+
-- Add csi_enabled column to kubernetes_cluster table - Move to 4.22
208+
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes', 'csi_enabled', 'TINYINT(1) unsigned NOT NULL DEFAULT 0 COMMENT "true if kubernetes cluster is using csi, false otherwise" ');

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,7 @@ public KubernetesClusterVO doInTransaction(TransactionStatus status) {
16041604
if (zone.isSecurityGroupEnabled()) {
16051605
newCluster.setSecurityGroupId(finalSecurityGroup.getId());
16061606
}
1607+
newCluster.setCsiEnabled(cmd.getEnableCsi());
16071608
kubernetesClusterDao.persist(newCluster);
16081609
addKubernetesClusterDetails(newCluster, defaultNetwork, cmd);
16091610
return newCluster;

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterVO.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ public class KubernetesClusterVO implements KubernetesCluster {
145145
@Column(name = "cni_config_details", updatable = true, length = 4096)
146146
private String cniConfigDetails;
147147

148+
@Column(name = "csi_enabled")
149+
private boolean csiEnabled;
150+
148151
@Override
149152
public long getId() {
150153
return id;
@@ -389,6 +392,14 @@ public void setClusterType(ClusterType clusterType) {
389392
this.clusterType = clusterType;
390393
}
391394

395+
public boolean isCsiEnabled() {
396+
return csiEnabled;
397+
}
398+
399+
public void setCsiEnabled(boolean csiEnabled) {
400+
this.csiEnabled = csiEnabled;
401+
}
402+
392403
public KubernetesClusterVO() {
393404
this.uuid = UUID.randomUUID().toString();
394405
}

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,14 @@ public class KubernetesClusterActionWorker {
231231

232232
protected final String deploySecretsScriptFilename = "deploy-cloudstack-secret";
233233
protected final String deployProviderScriptFilename = "deploy-provider";
234+
protected final String deployCsiDriverScriptFilename = "deploy-csi-driver";
234235
protected final String autoscaleScriptFilename = "autoscale-kube-cluster";
235236
protected final String validateNodeScript = "validate-cks-node";
236237
protected final String removeNodeFromClusterScript = "remove-node-from-cluster";
237238
protected final String scriptPath = "/opt/bin/";
238239
protected File deploySecretsScriptFile;
239240
protected File deployProviderScriptFile;
241+
protected File deployCsiDriverScriptFile;
240242
protected File autoscaleScriptFile;
241243
protected KubernetesClusterManagerImpl manager;
242244
protected String[] keys;
@@ -713,12 +715,14 @@ protected File retrieveScriptFile(String filename) {
713715
protected void retrieveScriptFiles() {
714716
deploySecretsScriptFile = retrieveScriptFile(deploySecretsScriptFilename);
715717
deployProviderScriptFile = retrieveScriptFile(deployProviderScriptFilename);
718+
deployCsiDriverScriptFile = retrieveScriptFile(deployCsiDriverScriptFilename);
716719
autoscaleScriptFile = retrieveScriptFile(autoscaleScriptFilename);
717720
}
718721

719722
protected void copyScripts(String nodeAddress, final int sshPort) {
720723
copyScriptFile(nodeAddress, sshPort, deploySecretsScriptFile, deploySecretsScriptFilename);
721724
copyScriptFile(nodeAddress, sshPort, deployProviderScriptFile, deployProviderScriptFilename);
725+
copyScriptFile(nodeAddress, sshPort, deployCsiDriverScriptFile, deployCsiDriverScriptFilename);
722726
copyScriptFile(nodeAddress, sshPort, autoscaleScriptFile, autoscaleScriptFilename);
723727
}
724728

@@ -819,6 +823,43 @@ protected boolean deployProvider() {
819823
}
820824
}
821825

826+
protected boolean deployCsiDriver() {
827+
File pkFile = getManagementServerSshPublicKeyFile();
828+
Pair<String, Integer> publicIpSshPort = getKubernetesClusterServerIpSshPort(null);
829+
publicIpAddress = publicIpSshPort.first();
830+
sshPort = publicIpSshPort.second();
831+
832+
try {
833+
String command = String.format("sudo %s/%s", scriptPath, deployCsiDriverScriptFilename);
834+
Pair<Boolean, String> result = SshHelper.sshExecute(publicIpAddress, sshPort, getControlNodeLoginUser(),
835+
pkFile, null, command, 10000, 10000, 60000);
836+
837+
// Maybe the file isn't present. Try and copy it
838+
if (!result.first()) {
839+
logMessage(Level.INFO, "CSI files missing. Adding them now", null);
840+
retrieveScriptFiles();
841+
copyScripts(publicIpAddress, sshPort);
842+
843+
if (!createCloudStackSecret(keys)) {
844+
logTransitStateAndThrow(Level.ERROR, String.format("Failed to setup keys for Kubernetes cluster %s",
845+
kubernetesCluster.getName()), kubernetesCluster.getId(), KubernetesCluster.Event.OperationFailed);
846+
}
847+
848+
// If at first you don't succeed ...
849+
result = SshHelper.sshExecute(publicIpAddress, sshPort, getControlNodeLoginUser(),
850+
pkFile, null, command, 10000, 10000, 60000);
851+
if (!result.first()) {
852+
throw new CloudRuntimeException(result.second());
853+
}
854+
}
855+
return true;
856+
} catch (Exception e) {
857+
String msg = String.format("Failed to deploy kubernetes provider: %s : %s", kubernetesCluster.getName(), e.getMessage());
858+
logAndThrow(Level.ERROR, msg);
859+
return false;
860+
}
861+
}
862+
822863
public void setKeys(String[] keys) {
823864
this.keys = keys;
824865
}

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ private boolean isKubernetesVersionSupportsHA() {
143143

144144
private Pair<String, String> getKubernetesControlNodeConfig(final String controlNodeIp, final String serverIp,
145145
final List<Network.IpAddresses> etcdIps, final String hostName, final boolean haSupported,
146-
final boolean ejectIso, final boolean externalCni) throws IOException {
146+
final boolean ejectIso, final boolean externalCni, final boolean setupCsi) throws IOException {
147147
String k8sControlNodeConfig = readK8sConfigFile("/conf/k8s-control-node.yml");
148148
final String apiServerCert = "{{ k8s_control_node.apiserver.crt }}";
149149
final String apiServerKey = "{{ k8s_control_node.apiserver.key }}";
@@ -161,6 +161,7 @@ private Pair<String, String> getKubernetesControlNodeConfig(final String control
161161
final String certSans = "{{ k8s_control.server_ips }}";
162162
final String k8sCertificate = "{{ k8s_control.certificate_key }}";
163163
final String externalCniPlugin = "{{ k8s.external.cni.plugin }}";
164+
final String setupCsiDriver = "{{ k8s.setup.csi.driver }}";
164165

165166
final List<String> addresses = new ArrayList<>();
166167
addresses.add(controlNodeIp);
@@ -212,6 +213,7 @@ private Pair<String, String> getKubernetesControlNodeConfig(final String control
212213
k8sControlNodeConfig = k8sControlNodeConfig.replace(certSans, String.format("- %s", serverIp));
213214
k8sControlNodeConfig = k8sControlNodeConfig.replace(k8sCertificate, KubernetesClusterUtil.generateClusterHACertificateKey(kubernetesCluster));
214215
k8sControlNodeConfig = k8sControlNodeConfig.replace(externalCniPlugin, String.valueOf(externalCni));
216+
k8sControlNodeConfig = k8sControlNodeConfig.replace(setupCsiDriver, String.valueOf(setupCsi));
215217

216218
k8sControlNodeConfig = updateKubeConfigWithRegistryDetails(k8sControlNodeConfig);
217219

@@ -246,7 +248,7 @@ private Pair<UserVm,String> createKubernetesControlNode(final Network network, S
246248
Long userDataId = kubernetesCluster.getCniConfigId();
247249
Pair<String, String> k8sControlNodeConfigAndControlIp = new Pair<>(null, null);
248250
try {
249-
k8sControlNodeConfigAndControlIp = getKubernetesControlNodeConfig(controlNodeIp, serverIp, etcdIps, hostName, haSupported, Hypervisor.HypervisorType.VMware.equals(clusterTemplate.getHypervisorType()), Objects.nonNull(userDataId));
251+
k8sControlNodeConfigAndControlIp = getKubernetesControlNodeConfig(controlNodeIp, serverIp, etcdIps, hostName, haSupported, Hypervisor.HypervisorType.VMware.equals(clusterTemplate.getHypervisorType()), Objects.nonNull(userDataId), kubernetesCluster.isCsiEnabled());
250252
} catch (IOException e) {
251253
logAndThrow(Level.ERROR, "Failed to read Kubernetes control node configuration file", e);
252254
}
@@ -858,6 +860,9 @@ public boolean startKubernetesClusterOnCreate(Long domainId, Long accountId, Lon
858860
}
859861
taintControlNodes();
860862
deployProvider();
863+
if (kubernetesCluster.isCsiEnabled()) {
864+
deployCsiDriver();
865+
}
861866
updateLoginUserDetails(clusterVMs.stream().map(InternalIdentity::getId).collect(Collectors.toList()));
862867
stateTransitTo(kubernetesCluster.getId(), KubernetesCluster.Event.OperationSucceeded);
863868
return true;

plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
207207
since = "4.21.0")
208208
private Map cniConfigDetails;
209209

210+
@Parameter(name = ApiConstants.ENABLE_CSI, type = CommandType.BOOLEAN, description = "if true, setups up CloudStack CSI driver", since = "4.21.0")
211+
private Boolean enableCsi;
212+
210213
@Parameter(name=ApiConstants.AS_NUMBER, type=CommandType.LONG, description="the AS Number of the network")
211214
private Long asNumber;
212215

@@ -371,6 +374,10 @@ public Long getCniConfigId() {
371374
return cniConfigId;
372375
}
373376

377+
public boolean getEnableCsi() {
378+
return Objects.nonNull(enableCsi) ? enableCsi : Boolean.FALSE;
379+
}
380+
374381
/////////////////////////////////////////////////////
375382
/////////////// API Implementation///////////////////
376383
/////////////////////////////////////////////////////

plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ write_files:
179179
mkdir -p /opt/provider
180180
cp "${BINARIES_DIR}/provider.yaml" /opt/provider/provider.yaml
181181
fi
182+
if [ -e "${BINARIES_DIR}/snapshot-crds.yaml" ]; then
183+
mkdir -p /opt/csi
184+
cp "${BINARIES_DIR}/snapshot-crds.yaml" /opt/csi/snapshot-crds.yaml
185+
cp "${BINARIES_DIR}/manifest.yaml" /opt/csi/manifest.yaml
186+
fi
182187
183188
PAUSE_IMAGE=`ctr -n k8s.io images ls -q | grep "pause" | sort | tail -n 1`
184189
echo $PAUSE_IMAGE
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/bin/bash -e
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
19+
(/opt/bin/kubectl get pods -A | grep cloud-controller-manager) && exit 0
20+
21+
if [ -e /opt/csi/snapshot-crds.yaml ]; then
22+
/opt/bin/kubectl apply -f /opt/csi/snapshot-crds.yaml
23+
sleep 5
24+
/opt/bin/kubectl apply -f /opt/csi/manifest.yaml
25+
exit 0
26+
else
27+
TARGET_DIR="/opt/csi"
28+
mkdir -p "$TARGET_DIR"
29+
# CSI_URLS=(
30+
# "https://github.com/shapeblue/cloudstack-csi-driver/releases/download/v3.0.0/snapshot-crds.yaml"
31+
# "https://github.com/shapeblue/cloudstack-csi-driver/releases/download/v3.0.0/manifest.yaml"
32+
# )
33+
CSI_URLS=(
34+
"http://10.0.3.130/cks/csi/snapshot-crds.yaml -O ${working_dir}/snapshot-crds.yaml"
35+
"http://10.0.3.130/cks/csi/manifest.yaml -O ${working_dir}/manifest.yaml"
36+
)
37+
for url in "${URLS[@]}"; do
38+
filename=$(basename "$url")
39+
40+
curl -sSL ${url} -o ${filename}
41+
if [ $? -ne 0 ]; then
42+
echo "Unable to connect to the internet to download the relevant files to install and setup CloudStack CSI driver"
43+
exit 1
44+
else
45+
/opt/bin/kubectl apply -f /opt/csi/snapshot-crds.yaml
46+
/opt/bin/kubectl apply -f /opt/csi/manifest.yaml
47+
exit 0
48+
fi
49+
done
50+
fi

0 commit comments

Comments
 (0)