chore: fix permission issues with running watcher sudoless

This commit is contained in:
Nicolas Meienberger 2023-08-22 07:48:59 +02:00 committed by Nicolas Meienberger
parent 8da6bed609
commit 9d525bfc71
7 changed files with 1878 additions and 61 deletions

View file

@ -23,7 +23,7 @@
"build:next": "next build",
"start:dev-container": "./.devcontainer/filewatcher.sh && npm run start:dev",
"start:rc": "docker compose -f docker-compose.rc.yml --env-file .env up --build",
"start:dev": "npm run prepare && docker compose -f docker-compose.dev.yml up",
"start:dev": "npm run prepare && docker compose -f docker-compose.dev.yml up --build",
"start:e2e": "./scripts/start-e2e.sh latest",
"start:pg": "docker run --name test-db -p 5433:5432 -d --rm -e POSTGRES_PASSWORD=postgres postgres:14",
"version": "echo $npm_package_version",

View file

@ -46,28 +46,27 @@ export class AppExecutors {
return { appDataDirPath, appDirPath, configJsonPath, repoPath };
};
private ensurePermissions = async (appId: string) => {
const { appDataDirPath, configJsonPath } = this.getAppPaths(appId);
if (!(await pathExists(appDataDirPath))) {
this.logger.info(`Creating app ${appId} data dir`);
await fs.promises.mkdir(appDataDirPath, { recursive: true });
}
// private ensurePermissions = async (appId: string) => {
// const { appDataDirPath, configJsonPath } = this.getAppPaths(appId);
// if (!(await pathExists(appDataDirPath))) {
// this.logger.info(`Creating app ${appId} data dir`);
// await fs.promises.mkdir(appDataDirPath, { recursive: true });
// }
// Check if app requires special uid and gid
if (await pathExists(configJsonPath)) {
const config = appInfoSchema.parse(JSON.parse(await fs.promises.readFile(configJsonPath, 'utf-8')));
const { uid, gid } = config;
// // Check if app requires special uid and gid
// if (await pathExists(configJsonPath)) {
// const config = appInfoSchema.parse(JSON.parse(await fs.promises.readFile(configJsonPath, 'utf-8')));
// const { uid, gid } = config;
if (uid && gid) {
this.logger.info(`Setting uid and gid to ${uid}:${gid}`);
await execAsync(`chown -R' ${uid}:${gid} ${path.join(appDataDirPath, 'data')}`);
}
}
// if (uid && gid) {
// this.logger.info(`Setting uid and gid to ${uid}:${gid}`);
// await execAsync(`chown -R ${uid}:${gid} ${path.join(appDataDirPath, 'data')}`);
// }
// }
// Remove all .gitkeep files from app data dir
await execAsync(`find ${appDataDirPath} -name '.gitkeep' -exec rm -f {} \\;`);
await execAsync(`chmod -R a+rwx ${appDataDirPath}`);
};
// // Remove all .gitkeep files from app data dir
// await execAsync(`find ${appDataDirPath} -name '.gitkeep' -exec rm -f {} \\;`);
// };
/**
* Given an app id, ensures that the app folder exists in the apps folder
@ -133,6 +132,8 @@ export class AppExecutors {
await copyDataDir(appId);
}
// await this.ensurePermissions(appId);
// run docker-compose up
this.logger.info(`Running docker-compose up for app ${appId}`);
await compose(appId, 'up -d');
@ -223,7 +224,7 @@ export class AppExecutors {
this.logger.info(`Copying folder ${repoPath} to ${appDirPath}`);
await fs.promises.cp(repoPath, appDirPath, { recursive: true });
await this.ensurePermissions(appId);
// await this.ensurePermissions(appId);
await compose(appId, 'pull');

View file

@ -49,15 +49,10 @@ export class RepoExecutors {
this.logger.info(`Cloning repo ${repoUrl} to ${repoPath}`);
const { stdout, stderr } = await execAsync(`git clone ${repoUrl} ${repoPath}`);
if (stderr) {
this.logger.error(`Error cloning repo ${repoUrl}: ${stderr}`);
return { success: false, message: stderr };
}
await execAsync(`git clone ${repoUrl} ${repoPath}`);
this.logger.info(`Cloned repo ${repoUrl} to ${repoPath}`);
return { success: true, message: stdout };
return { success: true, message: '' };
} catch (err) {
return this.handleRepoError(err);
}

View file

@ -33,6 +33,7 @@ export class SystemExecutors {
fileLogger.error(`An error occurred: ${err.message}`);
return { success: false, message: err.message };
}
fileLogger.error(`An error occurred: ${err}`);
return { success: false, message: `An error occurred: ${err}` };
};
@ -49,6 +50,35 @@ export class SystemExecutors {
};
};
private ensureFilePermissions = async () => {
const { rootFolderHost } = getEnv();
console.log('Tipi is asking for your password to ensure file permissions are correct (performed only in runtipi folder)');
const filesAndFolders = [
path.join(rootFolderHost, 'apps'),
path.join(rootFolderHost, 'logs'),
path.join(rootFolderHost, 'media'),
path.join(rootFolderHost, 'repos'),
path.join(rootFolderHost, 'state'),
path.join(rootFolderHost, '.env'),
path.join(rootFolderHost, 'docker-compose.yml'),
];
// Give permission to read and write to all files and folders for the current user
await Promise.all(
filesAndFolders.map(async (fileOrFolder) => {
if (await pathExists(fileOrFolder)) {
if (process.getgid && process.getuid) {
await execAsync(`sudo chown -R ${process.getuid()}:${process.getgid()} ${fileOrFolder}`);
}
await execAsync(`sudo chmod -R 750 ${fileOrFolder}`);
}
}),
);
};
public systemInfo = async () => {
try {
const { rootFolderHost } = getEnv();
@ -105,6 +135,8 @@ export class SystemExecutors {
public start = async () => {
const spinner = new TerminalSpinner('Starting Tipi...');
try {
await this.ensureFilePermissions();
spinner.start();
spinner.setMessage('Copying system files...');
await copySystemFiles();

View file

@ -7,6 +7,18 @@ import { startWorker } from './services/watcher/watcher';
import { SystemExecutors } from './executors';
const main = async () => {
// Ensure the user is running as root
if (process.env.NODE_ENV === 'production' && (!process.getuid || process.getuid() !== 0 || !process.getgid || process.getgid() !== 0)) {
// console.error(chalk.red('✗'), 'Tipi CLI must be run as root');
// process.exit(1);
}
// Ensure the OS is linux
if (process.env.NODE_ENV === 'production' && process.platform !== 'linux') {
// console.error(chalk.red('✗'), 'Tipi CLI can only be run on Linux');
// process.exit(1);
}
program.description(description).version(version);
program

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,22 @@ if [[ "$ARCHITECTURE" == "armv7"* ]] || [[ "$ARCHITECTURE" == "i686" ]] || [[ "$
exit 1
fi
### --------------------------------
### CLI arguments
### --------------------------------
UPDATE="false"
while [ -n "${1-}" ]; do
case "$1" in
--update) UPDATE="true" ;;
--)
shift # The double dash makes them parameters
break
;;
*) echo "Option $1 not recognized" && exit 1 ;;
esac
shift
done
OS="$(cat /etc/[A-Za-z]*[_-][rv]e[lr]* | grep "^ID=" | cut -d= -f2 | uniq | tr '[:upper:]' '[:lower:]' | tr -d '"')"
SUB_OS="$(cat /etc/[A-Za-z]*[_-][rv]e[lr]* | grep "^ID_LIKE=" | cut -d= -f2 | uniq | tr '[:upper:]' '[:lower:]' | tr -d '"')"
@ -145,6 +161,7 @@ function check_dependency_and_install() {
# Example
# check_dependency_and_install "openssl"
LATEST_VERSION=$(curl -s https://api.github.com/repos/meienberger/runtipi/releases/latest | grep tag_name | cut -d '"' -f4)
LATEST_ASSET="runtipi-cli-linux-x64"
@ -154,9 +171,19 @@ fi
URL="https://github.com/meienberger/runtipi/releases/download/$LATEST_VERSION/$LATEST_ASSET"
mkdir -p ./runtipi
if [[ "${UPDATE}" == "false" ]]; then
mkdir -p runtipi
cd runtipi || exit
fi
curl --location "$URL" -o ./runtipi/runtipi-cli
sudo chmod +x ./runtipi/runtipi-cli
curl --location "$URL" -o ./runtipi-cli
sudo chmod +x ./runtipi-cli
sudo ./runtipi/runtipi-cli start
# Check if user is in docker group
if ! groups | grep -q docker; then
echo "User is not in docker group. Please make sure your user is in the docker group and restart the script."
echo "You can add your user to the docker group by running: 'sudo usermod -aG docker $USER' and then exit the shell and restart the script."
exit 1
fi
./runtipi-cli start