more robust code for setting filesystem mode/ownership, use TrueNAS api when available to facilitate sudo-less ssh user

Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
Travis Glenn Hansen
2022-02-28 09:37:32 -07:00
parent 13f625973a
commit d275eccfa4
6 changed files with 268 additions and 65 deletions
+70 -44
View File
@@ -1,3 +1,4 @@
const _ = require("lodash");
const { CsiBaseDriver } = require("../index");
const { GrpcError, grpc } = require("../../utils/grpc");
const sleep = require("../../utils/general").sleep;
@@ -453,6 +454,64 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
}
}
async setFilesystemMode(path, mode) {
const driver = this;
const execClient = this.getExecClient();
let command = execClient.buildCommand("chmod", [mode, path]);
if ((await driver.getWhoAmI()) != "root") {
command = (await driver.getSudoPath()) + " " + command;
}
driver.ctx.logger.verbose("set permission command: %s", command);
let response = await execClient.exec(command);
if (response.code != 0) {
throw new GrpcError(
grpc.status.UNKNOWN,
`error setting permissions on dataset: ${JSON.stringify(response)}`
);
}
}
async setFilesystemOwnership(path, user = false, group = false) {
const driver = this;
const execClient = this.getExecClient();
if (user === false || typeof user == "undefined" || user === null) {
user = "";
}
if (group === false || typeof group == "undefined" || group === null) {
group = "";
}
user = String(user);
group = String(group);
if (user.length < 1 && group.length < 1) {
return;
}
let command = execClient.buildCommand("chown", [
(user.length > 0 ? user : "") + ":" + (group.length > 0 ? group : ""),
path,
]);
if ((await driver.getWhoAmI()) != "root") {
command = (await driver.getSudoPath()) + " " + command;
}
driver.ctx.logger.verbose("set ownership command: %s", command);
let response = await execClient.exec(command);
if (response.code != 0) {
throw new GrpcError(
grpc.status.UNKNOWN,
`error setting ownership on dataset: ${JSON.stringify(response)}`
);
}
}
/**
* Ensure sane options are used etc
* true = ready
@@ -1013,10 +1072,6 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
await zb.zfs.set(datasetName, properties);
}
//datasetPermissionsMode: 0777,
//datasetPermissionsUser: "root",
//datasetPermissionsGroup: "wheel",
// get properties needed for remaining calls
properties = await zb.zfs.get(datasetName, [
"mountpoint",
@@ -1031,53 +1086,24 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
// set mode
if (this.options.zfs.datasetPermissionsMode) {
command = execClient.buildCommand("chmod", [
this.options.zfs.datasetPermissionsMode,
await driver.setFilesystemMode(
properties.mountpoint.value,
]);
if ((await this.getWhoAmI()) != "root") {
command = (await this.getSudoPath()) + " " + command;
}
driver.ctx.logger.verbose("set permission command: %s", command);
response = await execClient.exec(command);
if (response.code != 0) {
throw new GrpcError(
grpc.status.UNKNOWN,
`error setting permissions on dataset: ${JSON.stringify(
response
)}`
);
}
this.options.zfs.datasetPermissionsMode
);
}
// set ownership
if (
this.options.zfs.datasetPermissionsUser ||
this.options.zfs.datasetPermissionsGroup
String(_.get(this.options, "zfs.datasetPermissionsUser", "")).length >
0 ||
String(_.get(this.options, "zfs.datasetPermissionsGroup", ""))
.length > 0
) {
command = execClient.buildCommand("chown", [
(this.options.zfs.datasetPermissionsUser
? this.options.zfs.datasetPermissionsUser
: "") +
":" +
(this.options.zfs.datasetPermissionsGroup
? this.options.zfs.datasetPermissionsGroup
: ""),
await driver.setFilesystemOwnership(
properties.mountpoint.value,
]);
if ((await this.getWhoAmI()) != "root") {
command = (await this.getSudoPath()) + " " + command;
}
driver.ctx.logger.verbose("set ownership command: %s", command);
response = await execClient.exec(command);
if (response.code != 0) {
throw new GrpcError(
grpc.status.UNKNOWN,
`error setting ownership on dataset: ${JSON.stringify(response)}`
);
}
this.options.zfs.datasetPermissionsUser,
this.options.zfs.datasetPermissionsGroup
);
}
// set acls
+167 -2
View File
@@ -1657,9 +1657,143 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
}
}
async setFilesystemMode(path, mode) {
const httpClient = await this.getHttpClient();
const apiVersion = httpClient.getApiVersion();
switch (apiVersion) {
case 1:
return super.setFilesystemMode(...arguments);
case 2:
let perms = {
path,
mode: String(mode),
};
/*
{
"path": "string",
"mode": "string",
"uid": 0,
"gid": 0,
"options": {
"stripacl": false,
"recursive": false,
"traverse": false
}
}
*/
let response;
let endpoint;
endpoint = `/filesystem/setperm`;
response = await httpClient.post(endpoint, perms);
if (response.statusCode == 200) {
return;
}
throw new Error(JSON.stringify(response.body));
break;
default:
throw new GrpcError(
grpc.status.FAILED_PRECONDITION,
`invalid configuration: unknown apiVersion ${apiVersion}`
);
}
}
async setFilesystemOwnership(path, user = false, group = false) {
const httpClient = await this.getHttpClient();
const apiVersion = httpClient.getApiVersion();
if (user === false || typeof user == "undefined" || user === null) {
user = "";
}
if (group === false || typeof group == "undefined" || group === null) {
group = "";
}
user = String(user);
group = String(group);
if (user.length < 1 && group.length < 1) {
return;
}
switch (apiVersion) {
case 1:
return super.setFilesystemOwnership(...arguments);
case 2:
let perms = {
path,
};
// set ownership
// user
if (user.length > 0) {
if (String(user).match(/^[0-9]+$/) == null) {
throw new GrpcError(
grpc.status.FAILED_PRECONDITION,
`datasetPermissionsUser must be numeric: ${user}`
);
}
perms.uid = Number(user);
}
// group
if (group.length > 0) {
if (String(group).match(/^[0-9]+$/) == null) {
throw new GrpcError(
grpc.status.FAILED_PRECONDITION,
`datasetPermissionsGroup must be numeric: ${group}`
);
}
perms.gid = Number(group);
}
/*
{
"path": "string",
"mode": "string",
"uid": 0,
"gid": 0,
"options": {
"stripacl": false,
"recursive": false,
"traverse": false
}
}
*/
let response;
let endpoint;
endpoint = `/filesystem/setperm`;
response = await httpClient.post(endpoint, perms);
if (response.statusCode == 200) {
return;
}
throw new Error(JSON.stringify(response.body));
break;
default:
throw new GrpcError(
grpc.status.FAILED_PRECONDITION,
`invalid configuration: unknown apiVersion ${apiVersion}`
);
}
}
async expandVolume(call, datasetName) {
const driverShareType = this.getDriverShareType();
const execClient = this.getExecClient();
const httpClient = await this.getHttpClient();
const apiVersion = httpClient.getApiVersion();
const zb = await this.getZetabyte();
switch (driverShareType) {
@@ -1696,8 +1830,39 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
]);
reload = true;
} else {
command = execClient.buildCommand("/etc/rc.d/ctld", ["reload"]);
reload = true;
switch (apiVersion) {
case 1:
// use cli for now
command = execClient.buildCommand("/etc/rc.d/ctld", ["reload"]);
reload = true;
break;
case 2:
this.ctx.logger.verbose(
"FreeNAS reloading iscsi daemon using api"
);
// POST /service/reload
let payload = {
service: "iscsitarget", // api version of ctld, same name in SCALE as well
"service-control": {
ha_propagate: true,
},
};
let response = await httpClient.post("/service/reload", payload);
if (![200, 204].includes(response.statusCode)) {
throw new GrpcError(
grpc.status.UNKNOWN,
`error reloading iscsi daemon - code: ${
response.statusCode
} body: ${JSON.stringify(response.body)}`
);
}
return;
default:
throw new GrpcError(
grpc.status.FAILED_PRECONDITION,
`invalid configuration: unknown apiVersion ${apiVersion}`
);
}
}
if (reload) {