objectivefs refinement, better iscsi session handling

Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
Travis Glenn Hansen 2024-03-02 11:44:45 -07:00
parent d70b45b909
commit ed32cf8db0
9 changed files with 118 additions and 114 deletions

View File

@ -16,6 +16,7 @@ if [[ -n "${IMAGE_TAG}" ]]; then
docker buildx build --progress plain --pull --push --platform "${DOCKER_BUILD_PLATFORM}" -t ${DOCKER_REPO}:${IMAGE_TAG} \
--label "org.opencontainers.image.created=$(date -u --iso-8601=seconds)" \
--label "org.opencontainers.image.revision=${GITHUB_SHA}" \
--build-arg OBJECTIVEFS_DOWNLOAD_ID=${OBJECTIVEFS_DOWNLOAD_ID} \
.
else
:

View File

@ -464,6 +464,7 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }}
GHCR_PASSWORD: ${{ secrets.GHCR_PASSWORD }}
OBJECTIVEFS_DOWNLOAD_ID: ${{ secrets.OBJECTIVEFS_DOWNLOAD_ID }}
DOCKER_CLI_EXPERIMENTAL: enabled
DOCKER_BUILD_PLATFORM: linux/amd64,linux/arm64,linux/arm/v7,linux/s390x,linux/ppc64le
IMAGE_TAG: ${{needs.determine-image-tag.outputs.tag}}

View File

@ -9,7 +9,7 @@ ARG BUILDPLATFORM
RUN echo "I am running build on $BUILDPLATFORM, building for $TARGETPLATFORM"
RUN apt-get update && apt-get install -y locales && rm -rf /var/lib/apt/lists/* \
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
ENV LANG=en_US.utf8
ENV NODE_VERSION=v20.11.1
@ -26,8 +26,8 @@ ENV PATH=/usr/local/lib/nodejs/bin:$PATH
# Run as a non-root user
RUN useradd --create-home csi \
&& mkdir /home/csi/app \
&& chown -R csi: /home/csi
&& mkdir /home/csi/app \
&& chown -R csi: /home/csi
WORKDIR /home/csi/app
USER csi
@ -50,21 +50,22 @@ ENV DEBIAN_FRONTEND=noninteractive
ARG TARGETPLATFORM
ARG BUILDPLATFORM
ARG OBJECTIVEFS_DOWNLOAD_ID
RUN echo "I am running on final $BUILDPLATFORM, building for $TARGETPLATFORM"
RUN apt-get update && apt-get install -y locales && rm -rf /var/lib/apt/lists/* \
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
ENV LANG=en_US.utf8
ENV NODE_ENV=production
# Workaround for https://github.com/nodejs/node/issues/37219
RUN test $(uname -m) != armv7l || ( \
apt-get update \
&& apt-get install -y libatomic1 \
&& rm -rf /var/lib/apt/lists/* \
)
apt-get update \
&& apt-get install -y libatomic1 \
&& rm -rf /var/lib/apt/lists/* \
)
# install node
#ENV PATH=/usr/local/lib/nodejs/bin:$PATH
@ -75,8 +76,8 @@ COPY --from=build /usr/local/lib/nodejs/bin/node /usr/local/bin/node
# netbase is required by rpcbind/rpcinfo to work properly
# /etc/{services,rpc} are required
RUN apt-get update && \
apt-get install -y wget netbase socat e2fsprogs exfatprogs xfsprogs btrfs-progs fatresize dosfstools ntfs-3g nfs-common cifs-utils fdisk gdisk cloud-guest-utils sudo rsync procps util-linux nvme-cli fuse && \
rm -rf /var/lib/apt/lists/*
apt-get install -y wget netbase socat e2fsprogs exfatprogs xfsprogs btrfs-progs fatresize dosfstools ntfs-3g nfs-common cifs-utils fdisk gdisk cloud-guest-utils sudo rsync procps util-linux nvme-cli fuse && \
rm -rf /var/lib/apt/lists/*
# controller requirements
#RUN apt-get update && \
@ -84,7 +85,7 @@ RUN apt-get update && \
# rm -rf /var/lib/apt/lists/*
# install objectivefs
ENV OBJECTIVEFS_VERSION=7.1
ENV OBJECTIVEFS_VERSION=7.2
ADD docker/objectivefs-installer.sh /usr/local/sbin
RUN chmod +x /usr/local/sbin/objectivefs-installer.sh && objectivefs-installer.sh
@ -112,7 +113,7 @@ RUN chmod +x /usr/local/bin/oneclient
# Run as a non-root user
RUN useradd --create-home csi \
&& chown -R csi: /home/csi
&& chown -R csi: /home/csi
COPY --from=build --chown=csi:csi /home/csi/app /home/csi/app

View File

@ -29,7 +29,7 @@ export DEB_FILE="objectivefs_${OBJECTIVEFS_VERSION}_${OBJECTIVEFS_ARCH}.deb"
echo "I am installing objectivefs $OBJECTIVEFS_VERSION"
wget "https://objectivefs.com/user/download/ac24htfht/${DEB_FILE}"
wget "https://objectivefs.com/user/download/${OBJECTIVEFS_DOWNLOAD_ID}/${DEB_FILE}"
dpkg -i "${DEB_FILE}"
rm "${DEB_FILE}"

View File

@ -592,75 +592,6 @@ class ControllerObjectiveFSDriver extends CsiBaseDriver {
grpc.status.UNIMPLEMENTED,
`operation not supported by driver`
);
const driver = this;
// both these are required
let source_volume_id = call.request.source_volume_id;
let name = call.request.name;
if (!source_volume_id) {
throw new GrpcError(
grpc.status.INVALID_ARGUMENT,
`snapshot source_volume_id is required`
);
}
source_volume_id = source_volume_id.toLowerCase();
if (!name) {
throw new GrpcError(
grpc.status.INVALID_ARGUMENT,
`snapshot name is required`
);
}
driver.ctx.logger.verbose("requested snapshot name: %s", name);
let invalid_chars;
invalid_chars = name.match(/[^a-z0-9_\-:.+]+/gi);
if (invalid_chars) {
invalid_chars = String.prototype.concat(
...new Set(invalid_chars.join(""))
);
throw new GrpcError(
grpc.status.INVALID_ARGUMENT,
`snapshot name contains invalid characters: ${invalid_chars}`
);
}
// https://stackoverflow.com/questions/32106243/regex-to-remove-all-non-alpha-numeric-and-replace-spaces-with/32106277
name = name.replace(/[^a-z0-9_\-:.+]+/gi, "");
driver.ctx.logger.verbose("cleansed snapshot name: %s", name);
const snapshot_id = `${source_volume_id}-${name}`;
const volume_path = driver.getControllerVolumePath(source_volume_id);
const snapshot_path = driver.getControllerSnapshotPath(snapshot_id);
// do NOT overwrite existing snapshot
if (!(await driver.directoryExists(snapshot_path))) {
await driver.cloneDir(volume_path, snapshot_path);
}
let size_bytes = await driver.getDirectoryUsage(snapshot_path);
return {
snapshot: {
/**
* The purpose of this field is to give CO guidance on how much space
* is needed to create a volume from this snapshot.
*/
size_bytes,
snapshot_id,
source_volume_id: source_volume_id,
//https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto
creation_time: {
seconds: Math.round(new Date().getTime() / 1000),
nanos: 0,
},
ready_to_use: true,
},
};
}
/**
@ -674,19 +605,6 @@ class ControllerObjectiveFSDriver extends CsiBaseDriver {
grpc.status.UNIMPLEMENTED,
`operation not supported by driver`
);
const driver = this;
const snapshot_id = call.request.snapshot_id;
if (!snapshot_id) {
throw new GrpcError(
grpc.status.INVALID_ARGUMENT,
`snapshot_id is required`
);
}
return {};
}
/**

View File

@ -1265,11 +1265,6 @@ class CsiBaseDriver {
let objectivefs = driver.getDefaultObjectiveFSInstance();
let ofs_filesystem = volume_context.filesystem;
let env = {};
for (const key in volume_context) {
if (key.startsWith("env.")) {
env[key.substr("env.".length)] = volume_context[key];
}
}
for (const key in normalizedSecrets) {
if (key.startsWith("env.")) {
@ -1277,7 +1272,11 @@ class CsiBaseDriver {
}
}
let ofs_object_store = env["OBJECTSTORE"];
for (const key in volume_context) {
if (key.startsWith("env.")) {
env[key.substr("env.".length)] = volume_context[key];
}
}
if (!ofs_filesystem) {
throw new GrpcError(
@ -1286,6 +1285,16 @@ class CsiBaseDriver {
);
}
let ofs_object_store = env["OBJECTSTORE"];
if (!ofs_object_store) {
ofs_object_store = await objectivefs.getObjectStoreFromFilesystem(
ofs_filesystem
);
if (ofs_object_store) {
env["OBJECTSTORE"] = ofs_object_store;
}
}
if (!ofs_object_store) {
throw new GrpcError(
grpc.status.FAILED_PRECONDITION,
@ -1293,6 +1302,11 @@ class CsiBaseDriver {
);
}
// normalize fs to not include objectstore
ofs_filesystem = await objectivefs.stripObjectStoreFromFilesystem(
ofs_filesystem
);
device = `${ofs_object_store}${ofs_filesystem}`;
result = await mount.deviceIsMountedAtPath(
device,

View File

@ -181,6 +181,20 @@ function stringify(value) {
return JSON.stringify(value, getCircularReplacer());
}
function before_string(target, search) {
if (!target.includes(search)) {
return "";
}
return target.substring(0, target.indexOf(search));
}
function after_string(target, search) {
if (!target.includes(search)) {
return "";
}
return target.substring(target.indexOf(search) + search.length);
}
function default_supported_block_filesystems() {
return ["btrfs", "exfat", "ext3", "ext4", "ext4dev", "ntfs", "vfat", "xfs"];
}
@ -266,6 +280,8 @@ module.exports.crc8 = crc8;
module.exports.lockKeysFromRequest = lockKeysFromRequest;
module.exports.getLargestNumber = getLargestNumber;
module.exports.stringify = stringify;
module.exports.before_string = before_string;
module.exports.after_string = after_string;
module.exports.stripWindowsDriveLetter = stripWindowsDriveLetter;
module.exports.hasWindowsDriveLetter = hasWindowsDriveLetter;
module.exports.axios_request = axios_request;

View File

@ -1,5 +1,6 @@
const cp = require("child_process");
const { sleep } = require("./general");
const { hostname_lookup, sleep } = require("./general");
const net = require("net");
function getIscsiValue(value) {
if (value == "<empty>") return null;
@ -179,12 +180,34 @@ class ISCSI {
const sessions = await iscsi.iscsiadm.getSessions();
let parsedPortal = iscsi.parsePortal(portal);
let parsedPortalHostIP = "";
if (parsedPortal.host) {
// if host is not an ip address
if (net.isIP(parsePortal.host) == 0) {
// ipv6 response is without []
parsedPortalHostIP =
(await hostname_lookup(parsedPortal.host)) || "";
}
}
// set invalid hostname/ip string to ensure empty values do not errantly pass
if (!parsedPortalHostIP) {
parsedPortalHostIP = "--------------------------------------";
}
let session = false;
sessions.every((i_session) => {
// [2a10:4741:36:28:e61d:2dff:fe90:80fe]:3260
// i_session.portal includes [] for ipv6
if (
`${i_session.iqn}` == tgtIQN &&
(portal == i_session.portal ||
`[${parsedPortal.host}]:${parsedPortal.port}` == i_session.portal)
`${parsedPortal.host}:${parsedPortal.port}` == i_session.portal ||
`${parsedPortalHostIP}:${parsedPortal.port}` ==
i_session.portal ||
`[${parsedPortal.host}]:${parsedPortal.port}` ==
i_session.portal ||
`[${parsedPortalHostIP}]:${parsedPortal.port}` ==
i_session.portal)
) {
session = i_session;
return false;

View File

@ -1,9 +1,13 @@
const cp = require("child_process");
const GeneralUtils = require("./general");
const DEFAULT_TIMEOUT = process.env.MOUNT_DEFAULT_TIMEOUT || 30000;
const EXIT_CODE_64 = "administrator can not mount filesystems";
const EXIT_CODE_78 = "missing or invalid passphrase";
const EXIT_CODES = {
64: "administrator can not mount filesystems",
65: "unable to decrypt using passphrase",
78: "missing or invalid passphrase",
};
/**
* https://objectivefs.com/
@ -112,10 +116,30 @@ class ObjectiveFS {
* @param {*} options
*/
async destroy(env, filesystem, options = []) {
const objectivefs = this;
if (!env) {
env = {};
}
const objectivefs = this;
/**
* delete safety checks for filesystem
*
* while it is possible to delete a fs without a pool we
* should never be doing that in democratic-csi
*/
let fs_parts = filesystem.split("/");
if (fs_parts.length != 2) {
throw new Error(`filesystem safety check failed for fs: ${filesystem}`);
}
if (!fs_parts[0]) {
throw new Error(`filesystem safety check failed for fs: ${filesystem}`);
}
if (!fs_parts[1]) {
throw new Error(`filesystem safety check failed for fs: ${filesystem}`);
}
let args = ["destroy"];
args = args.concat(options);
args = args.concat([filesystem]);
@ -237,6 +261,18 @@ class ObjectiveFS {
}
}
async getObjectStoreFromFilesystem(filesystem) {
if (filesystem.includes("://")) {
return GeneralUtils.before_string("://");
}
}
async stripObjectStoreFromFilesystem(filesystem) {
if (filesystem.includes("://")) {
return GeneralUtils.after_string("://");
}
}
exec(command, args, options = {}) {
if (!options.hasOwnProperty("timeout")) {
options.timeout = DEFAULT_TIMEOUT;
@ -250,9 +286,7 @@ class ObjectiveFS {
command = objectivefs.options.paths.sudo;
}
// OBJECTIVEFS_ENV
options.env = { ...{}, ...objectivefs.options.env, ...options.env };
//console.log(options);
// truncate admin key during mount operations
if (options.operation == "mount") {
@ -296,12 +330,8 @@ class ObjectiveFS {
});
child.on("close", function (code) {
if (code == 78 && !stderr) {
stderr += EXIT_CODE_78;
}
if (code == 64 && !stderr) {
stderr += EXIT_CODE_64;
if (!stderr && EXIT_CODES[code]) {
stderr += EXIT_CODES[code];
}
const result = { code, stdout, stderr, timeout: false };