chore: fix permission issues with running watcher sudoless
This commit is contained in:
parent
8da6bed609
commit
9d525bfc71
7 changed files with 1878 additions and 61 deletions
|
@ -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",
|
||||
|
|
|
@ -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');
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
1808
pnpm-lock.yaml
1808
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue