Skip to content

Commit fb9b008

Browse files
authored
Add files via upload
Initial import
1 parent 885d85f commit fb9b008

29 files changed

+2930
-1
lines changed

Dockerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Use an official Python runtime as a parent image
2+
#Choose a lightweight base image
3+
FROM python:3.9-slim
4+
5+
6+
# Install ps package for process management
7+
RUN apt-get update && apt-get install -y procps
8+
# Set the working directory in the container
9+
# Change this to your application's directory
10+
WORKDIR /app
11+
12+
# Copy the requirements file into the container
13+
# Assumes you have a `requirements.txt` file with dependencies
14+
COPY requirements.txt .
15+
16+
# Install any dependencies specified in the requirements file
17+
RUN pip install --no-cache-dir -r requirements.txt
18+
19+
# Copy the current directory contents into the container
20+
COPY *.py .
21+
COPY ./templates ./templates
22+
23+
# Set the environment variables
24+
ENV FLASK_APP=app.py
25+
# Expose the port the app runs on
26+
EXPOSE 5003
27+
28+
# Run the Flask app
29+
#CMD ["flask", "run", "--host=0.0.0.0", "--port=5003"]
30+
# Command to run the application with Gunicorn
31+
CMD ["gunicorn", "-b", "0.0.0.0:5003", "app:app"]

README.md

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,141 @@
1-
Initial readme
1+
2+
---
3+
4+
# RsyncWebApp
5+
6+
**RsyncWebApp** is a remote server rsync configuration tool designed to streamline the setup and management of rsync tasks on remote servers. This app allows you to log in to a remote server, configure rsync tasks, and save them to a shell script or directly to `crontab` for automated execution. Additionally, RsyncWebApp can discover SMB shares and generate mount scripts for easier access and management of shared network resources.
7+
8+
## Features (The app has not been fully tested, please test before adoption).
9+
10+
- **Remote Rsync Configuration**: Log on to a remote server and configure rsync tasks for data synchronization.
11+
- **Save to Shell or Crontab**: Save tasks to a shell script or directly to `crontab` for scheduled execution on the server.
12+
- **Execute Commands Remotely**: Execute saved shell or crontab commands directly on the remote server.
13+
- **SMB Share Discovery**: Discover available SMB shares and create mount scripts to connect to these shares.
14+
- **Docker Deployment**: Quickly deploy the app using the included `docker-compose.yml` file.
15+
16+
## Getting Started
17+
18+
### Prerequisites
19+
20+
- **Docker** and **Docker Compose**: Ensure Docker and Docker Compose are installed on your system to use the containerized deployment option.
21+
- **Python 3.x** and **Flask**: If running the app directly, you'll need Python 3.x and Flask installed.
22+
23+
### Installation and Setup
24+
25+
#### 1. Clone the Repository
26+
Clone this repository to your local machine:
27+
```bash
28+
git clone https://github.com/yourusername/rsyncwebapp.git
29+
cd rsyncwebapp
30+
```
31+
Create secrets.env in the app root directory with this content
32+
```bash
33+
SECRET_KEY='yoursupersecretkeycombination'
34+
```
35+
36+
37+
#### 2. Docker Deployment
38+
To deploy using Docker Compose:
39+
- Start the app with the following command:
40+
```bash
41+
docker-compose up -d
42+
```
43+
- The app will be accessible on the ports specified in the `docker-compose.yml` file. Adjust port mappings if needed to avoid conflicts.
44+
45+
#### 3. Manual Deployment
46+
If you prefer to run the app directly with Python and Flask:
47+
- Install the necessary dependencies:
48+
```bash
49+
pip install -r requirements.txt
50+
```
51+
- Start the Flask app:
52+
```bash
53+
python app.py
54+
```
55+
- By default, Flask will serve the app on port 5003, but this can be customized in `app.py`.
56+
57+
#### 4. For dev:
58+
```bash
59+
python3 -m venv venv
60+
source venv/bin/activate
61+
pip install --no-cache-dir -r requirements.txt
62+
python app.py
63+
64+
```
65+
### Usage
66+
67+
1. **Login to Remote Server**
68+
- Authenticate with a remote server using your credentials. This will allow you to set up rsync tasks and execute commands on the remote server.
69+
70+
2. **Configure Rsync Task**
71+
- Once logged in, define the rsync options, source, and destination paths. Customize rsync flags for options like `--delete` to remove extraneous files, `--archive` to preserve permissions, and more.
72+
73+
3. **Save and Execute**
74+
- Choose to save the rsync task to a shell script or directly to `crontab`.
75+
- For saved tasks:
76+
- **Shell Script**: This creates a `.sh` file that you can execute manually or with a scheduler.
77+
- **Crontab**: Save tasks directly to the server’s `crontab` for automatic execution based on your specified schedule.
78+
79+
4. **Discover SMB Shares**
80+
- Use the SMB discovery tool to scan for available SMB shares within your network.
81+
- Generate mount scripts to easily mount SMB shares on your server or local machine.
82+
83+
5. **Files**
84+
- All yaml and shell files are in the /home/user/rsyncwebapp directory.
85+
86+
### Configuration
87+
88+
- The application’s exposed ports, network configuration, and environment variables can be adjusted within the `docker-compose.yml` file.
89+
- The default Flask server port can also be configured in `app.py` if running outside of Docker.
90+
91+
### Example Docker Compose Configuration
92+
93+
Here’s a snippet of what your `docker-compose.yml` might look like:
94+
95+
```yaml
96+
services:
97+
rsyncwebapp:
98+
hostname: rsyncwebapp-container
99+
build: . # Build the Docker image from the current directory
100+
container_name: rsyncwebapp
101+
ports:
102+
- "8003:5003/tcp" # Map the container port to the host port
103+
environment:
104+
FLASK_ENV: 'production'
105+
FLASK_APP: "app.py"
106+
FLASK_DEBUG: "0"
107+
env_file:
108+
- secrets.env
109+
volumes:
110+
- /var/run/docker.sock:/var/run/docker.sock
111+
- /etc/localtime:/etc/localtime:ro
112+
- /etc/timezone:/etc/timezone:ro
113+
- .:/app # Mount the current directory to the container's `/app`
114+
115+
```
116+
117+
To change the default port or environment variables, simply edit this file before running `docker-compose up`.
118+
119+
## Contributing
120+
121+
Contributions are welcome! If you'd like to contribute, please fork the repository and submit a pull request with your changes. You can also open an issue to discuss any improvements or new features.
122+
123+
1. Fork the Project
124+
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
125+
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
126+
4. Push to the Branch (`git push origin feature/AmazingFeature`)
127+
5. Open a Pull Request
128+
129+
## License
130+
131+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
132+
133+
## Acknowledgments
134+
135+
- **Flask** for the web framework.
136+
- **Docker** and **Docker Compose** for containerization.
137+
- **Rsync** and **SMB tools** for the core functionality.
138+
139+
---
140+
141+
**RsyncWebApp** is your streamlined solution for managing rsync tasks and SMB shares on remote servers.

app.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
from flask import Flask, render_template, request, redirect, url_for, flash, session
2+
import paramiko
3+
from flask_session import Session
4+
import os
5+
import logging
6+
from yaml_handler import YAMLHandler # Import the refactored YAML handler
7+
from shAndCrontab import SHAndCRONTABHandler
8+
9+
10+
from browse import browse_blueprint # Blueprint for browsing directories
11+
from configure import configure_blueprint # Blueprint for configuring directory pairs
12+
from logs import log_blueprint # Import the blueprint for managing log files
13+
from view_tasks import view_tasks_blueprint
14+
from server_management import server_management_blueprint
15+
16+
from netbios import netbios_bp
17+
from smb_shares import smb_shares_bp
18+
19+
app = Flask(__name__)
20+
21+
app.config['ENV'] = os.environ.get("FLASK_ENV", "development")
22+
23+
logging.basicConfig(filename='app.log', level=logging.DEBUG)
24+
25+
app.secret_key = os.environ.get("SECRET_KEY", "default_secret_key")
26+
app.config['SESSION_TYPE'] = 'filesystem'
27+
Session(app)
28+
29+
app.register_blueprint(browse_blueprint, url_prefix="/browse")
30+
app.register_blueprint(configure_blueprint, url_prefix="/configure")
31+
app.register_blueprint(log_blueprint, url_prefix="/logs") # Optional prefix for the blueprint
32+
app.register_blueprint(view_tasks_blueprint, url_prefix="/view_tasks")
33+
app.register_blueprint(server_management_blueprint, url_prefix="/server_management")
34+
# Register the NetBIOS blueprint
35+
app.register_blueprint(netbios_bp, url_prefix='/netbios')
36+
app.register_blueprint(smb_shares_bp)
37+
38+
@app.route('/')
39+
def index():
40+
41+
flash(f"app Environment = {app.config['ENV']}",'info')
42+
43+
if 'logged_in' not in session:
44+
return redirect(url_for('login'))
45+
46+
hostname = os.uname().nodename
47+
48+
server = session.get('server', '')
49+
# Create a YAMLHandler instance with remote handling
50+
yaml_handler = YAMLHandler(use_remote=True)
51+
# Load YAML data
52+
yaml_data = yaml_handler.get_or_create_default_settings() # Load YAML data
53+
54+
log_files_dir = yaml_data[server].get('log_files_dir', None)
55+
# Get the directory pairs for the logged-in server
56+
if log_files_dir is None:
57+
log_files_dir = '/home/'+session['username']+'/rsyncwebapp'
58+
yaml_data[server]['log_files_dir'] = log_files_dir
59+
yaml_handler.save_yaml(yaml_data)
60+
61+
pairs = yaml_data[server].get('pairs', [])
62+
if not pairs:
63+
pairs = []
64+
yaml_data[server]['pairs'] = pairs
65+
yaml_handler.save_yaml(yaml_data)
66+
67+
# get server information
68+
server_data = yaml_data.get(server, [])
69+
70+
# get server information
71+
server_data = yaml_data.get(server, [])
72+
return render_template('index.html', hostname=hostname, server=server, logfiles=log_files_dir, server_data=pairs, enumerate=enumerate) # Pass 'enumerate'
73+
74+
@app.route('/remove_pair/<int:pair_index>', methods=['GET'])
75+
def remove_pair(pair_index):
76+
if 'logged_in' not in session:
77+
return redirect(url_for('login'))
78+
79+
server = session.get('server', '')
80+
# Create a YAMLHandler instance with remote handling
81+
yaml_handler = YAMLHandler(use_remote=True)
82+
# Load YAML data
83+
yaml_data = yaml_handler.load_yaml()
84+
85+
if server in yaml_data:
86+
directory_pairs = yaml_data[server].get('pairs', [])
87+
if 0 <= pair_index < len(directory_pairs):
88+
#remove from crontab and shell script if they exist
89+
shAndCrontab = SHAndCRONTABHandler(use_remote=True)
90+
shAndCrontab.remove_from_crontab(directory_pairs[pair_index])
91+
shAndCrontab.remove_from_script(directory_pairs[pair_index])
92+
93+
del directory_pairs[pair_index] # Remove the pair
94+
yaml_handler.save_yaml(yaml_data) # Persist changes
95+
flash("Pair removed successfully", "info")
96+
else:
97+
flash("Invalid pair index", "warning")
98+
else:
99+
flash("Server not found", "warning")
100+
101+
return redirect(url_for('index'))
102+
103+
@app.route('/login', methods=['GET', 'POST'])
104+
def login():
105+
hostname = os.uname().nodename
106+
if request.method == 'POST':
107+
server = request.form.get('server', 'hp-debian').strip()
108+
username = request.form.get('username', 'ghassan').strip()
109+
password = request.form.get('password', '').strip()
110+
private_key_path = request.form.get('private_key_path', '').strip()
111+
passphrase = request.form.get('passphrase', '').strip()
112+
113+
if not server or not username:
114+
flash("Server and username are required.", "warning")
115+
return render_template('login.html', hostname=hostname)
116+
117+
ssh = paramiko.SSHClient()
118+
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
119+
120+
try:
121+
if private_key_path:
122+
if not passphrase:
123+
flash("Passphrase is required for encrypted private keys.", 'warning')
124+
return render_template('login.html')
125+
126+
pkey = paramiko.RSAKey.from_private_key_file(private_key_path, password=passphrase)
127+
ssh.connect(server, username=username, pkey=pkey)
128+
else:
129+
ssh.connect(server, username=username, password=password)
130+
131+
# Create the app directory to store the app files
132+
stdin, stdout, stderr = ssh.exec_command(f"mkdir -p /home/{username}/rsyncwebapp")
133+
error = stderr.read().decode().strip()
134+
if error:
135+
flash(f"Directory creation failed: {error}", "danger")
136+
return render_template('login.html', hostname=hostname)
137+
138+
# Store session information
139+
session['logged_in'] = True
140+
session['server'] = server
141+
session['username'] = username
142+
session['password'] = password
143+
session['private_key_path'] = private_key_path
144+
session['passphrase'] = passphrase
145+
146+
# Assuming YAMLHandler class and yaml operations are defined elsewhere
147+
yaml_handler = YAMLHandler(use_remote=True)
148+
yaml_handler.ensure_yaml_file()
149+
150+
yaml_data = yaml_handler.load_yaml() # Load YAML data
151+
152+
return redirect(url_for('index'))
153+
154+
except paramiko.AuthenticationException:
155+
flash("Invalid username or password.", "danger")
156+
return render_template('login.html', hostname=hostname)
157+
158+
except paramiko.SSHException as e:
159+
flash(f"SSH connection failed: {e}", "danger")
160+
return render_template('login.html', hostname=hostname)
161+
162+
except Exception as e:
163+
flash(f"Login failed: {e}", "danger")
164+
return render_template('login.html', hostname=hostname)
165+
166+
return render_template('login.html', hostname=hostname)
167+
168+
@app.route('/logout')
169+
def logout():
170+
session.clear() # Clear session data
171+
return redirect(url_for('login'))
172+
173+
if __name__ == '__main__':
174+
logging.info("app config: %s\n ", app.config)
175+
176+
app.run(debug=True, host='0.0.0.0', port=5003)

0 commit comments

Comments
 (0)