Skip to content

Commit c0731bb

Browse files
authored
Merge pull request #77 from browserstack/one-click
CI: One click
2 parents 8abc425 + c991b6b commit c0731bb

9 files changed

+216
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 4.1.3 on 2023-02-19 12:26
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('Access', '0002_useridentity_delete_gitacces_remove_user_gitusername_and_more'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='useraccessmapping',
16+
name='fail_reason',
17+
field=models.TextField(blank=True, null=True),
18+
),
19+
migrations.AlterField(
20+
model_name='groupaccessmapping',
21+
name='group',
22+
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='group_access_mapping', to='Access.groupv2'),
23+
),
24+
]

Access/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,8 @@ def update_revoker(self, revoker):
272272
self.save()
273273

274274
def offboard(self, revoker):
275-
self.state = "offboarding"
276-
self.revoker = revoker
275+
self.change_state("offboarding")
276+
self.update_revoker(revoker)
277277
self.offbaord_date = datetime.datetime.now()
278278
self.user.is_active = False
279279
self.save()

Dockerfile

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# Set the base image to use to Ubuntu
66
FROM python:3.11-slim-buster AS base
77

8+
ENV DJANGO_SETTINGS_MODULE=BrowserStackAutomation.settings
89
RUN DEBIAN_FRONTEND=noninteractive \
910
apt-get update -y \
1011
&& apt-get install --no-install-recommends -y \
@@ -14,13 +15,14 @@ RUN DEBIAN_FRONTEND=noninteractive \
1415

1516
# Set env variables used in this Dockerfile (add a unique prefix, such as DEV)
1617
RUN apt update && apt install -y netcat dnsutils libmariadbclient-dev
17-
1818
RUN useradd -rm -d /home/app -s /bin/bash -g root -G sudo -u 1001 app
1919
WORKDIR /srv/code/dev
2020
RUN mkdir -p logs
2121
RUN chown -R app /srv/code/dev
2222
USER app
2323

24+
25+
2426
# Copy just requirements.txt
2527
COPY requirements.txt /tmp/requirements.txt
2628
COPY config.json.sample config.json
@@ -31,8 +33,7 @@ RUN pip install -r /tmp/requirements.txt --no-cache-dir --ignore-installed
3133
COPY --chown=app:root . .
3234

3335
FROM base as test
34-
ENTRYPOINT [ "python" ]
35-
CMD [ "-m", "pytest", "-v", "--cov", "--disable-warnings" ]
36+
CMD ["python" "-m", "pytest", "-v", "--cov", "--disable-warnings" ]
3637

3738
FROM base as web
3839
COPY ./docker-entrypoint.sh /tmp/entrypoint.sh

docker-compose.yml

+26-9
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,21 @@ version: '3'
33
services:
44
web:
55
container_name: dev
6-
image: ${DOCKERIMAGE}
76
build:
87
context: .
98
dockerfile: Dockerfile
109
target: web
1110
env_file:
1211
- ./secrets/ops_app_dev.env
1312
volumes:
14-
- .:/srv/code/dev
1513
- ./mounts/logs/:/ebs/logs/
1614
ports:
1715
- 8000:8000
1816
depends_on:
1917
- db
2018
command: >
21-
/bin/bash -c "
22-
while ! nc -z db 3306;
23-
do
24-
echo sleeping;
25-
sleep 1;
26-
done;
27-
echo Connected!;"
19+
bash -c "echo Starting Django runserver;
20+
python manage.py runserver 0.0.0.0:8000"
2821
db:
2922
container_name: db
3023
image: mysql/mysql-server:8.0.31
@@ -34,6 +27,30 @@ services:
3427
- ./secrets/ops_mysql_dev.env
3528
volumes:
3629
- ./dbs:/var/lib/mysql --socket=/tmp/mysql.sock
30+
redis:
31+
container_name: redis
32+
image: redis:alpine
33+
command: --port 6379
34+
ports:
35+
- "6379:6379"
36+
celery:
37+
container_name: celery
38+
build:
39+
context: .
40+
dockerfile: Dockerfile
41+
target: web
42+
volumes:
43+
- ./:/app/
44+
env_file:
45+
- ./secrets/ops_app_celery.env
46+
depends_on:
47+
- db
48+
- redis
49+
- web
50+
command: >
51+
bash -c "
52+
echo Starting celery;
53+
python3 -m celery -A BrowserStackAutomation worker -n worker1 -l DEBUG"
3754
test:
3855
container_name: test
3956
build:

docker-entrypoint.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ touch /ebs/logs/bstack.log
1111
tail -n 0 -f /ebs/logs/bstack.log &
1212

1313
# run scripts/clone_access_modules.py to clone access modules
14+
1415
python scripts/clone_access_modules.py
16+
pip install -r Access/access_modules/requirements.txt --no-cache-dir --ignore-installed
1517

16-
echo Starting Django runserver.
17-
python manage.py runserver 0.0.0.0:8000
18+
eval "$@"

docs/one-click-dev.md

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Setup for Local Development
2+
3+
## Pre-requisistes
4+
5+
### Install Docker
6+
7+
- For macOS(brew)
8+
```
9+
brew install docker docker-compose
10+
```
11+
- For windows/linux/macOS refer to
12+
https://docs.docker.com/get-docker/
13+
14+
### Install Docker Container Runtime
15+
https://github.com/abiosoft/colima
16+
```bash
17+
brew install colima
18+
colima start
19+
```
20+
21+
### Setup
22+
Clone the repo in local system
23+
```bash
24+
git clone https://github.com/browserstack/enigma-public-central.git
25+
```
26+
1. Create .env file from .env.sample file. Edit the DOCKERIMAGE to the latest image URL.
27+
2. copy config.json.sample to config.json
28+
```bash
29+
{
30+
"googleapi": {
31+
"SOCIAL_AUTH_GOOGLE_OAUTH2_KEY": "",
32+
"SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET": "",
33+
"SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS": ""
34+
},
35+
"database": {
36+
"engine": "sqlite3"
37+
},
38+
"access_modules": {
39+
"git_urls": [
40+
"https://github.com/browserstack/enigma-public-access-modules.git"
41+
]
42+
},
43+
"enigmaGroup": {
44+
"MAIL_APPROVER_GROUPS": [
45+
46+
]
47+
},
48+
"emails": {
49+
"access-approve": "<access-approve-email>"
50+
},
51+
"background_task_manager": {
52+
"type": "celery",
53+
"config": {
54+
"broker": "<celery-broker-url>",
55+
"backend": "<celery-result-backend-url>",
56+
"need_monitoring": true,
57+
"monitoring_apps": "django_celery_results"
58+
}
59+
}
60+
}
61+
```
62+
### for private repo in git_urls in `config.json`
63+
```bash
64+
"https://<git-username>:<github-token>@github.com/browserstack/enigma-public-access-modules.git"
65+
```
66+
where `github-token` is a pat token from https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token
67+
68+
69+
### Add the config of broker and database in `config.json`
70+
- For self-hosted celery
71+
```bash
72+
celery-broker-url="redis://localhost:6379/0"
73+
celery-result-backend-url="redis://localhost:6379/0"
74+
```
75+
- For self-hosted databases
76+
```bash
77+
celery-broker-url="redis://localhost:6379/0"
78+
celery-result-backend-url="db+mysql://root@localhost:3306/<name_of_db>"
79+
```
80+
### Add the config of custom access-module repos `config.json`
81+
82+
```bash
83+
"access_modules": {
84+
....
85+
86+
"aws_access": {
87+
"aws_accounts": [
88+
{
89+
"account": "<your-account>",
90+
"access_key_id": "<access_key_id>",
91+
"secret_access_key": "<secret_access_key>"
92+
}
93+
]
94+
},
95+
.....
96+
},
97+
```
98+
Add configuration for all access_module as here added for aws_access.
99+
100+
3. Start the service
101+
```bash
102+
make dev
103+
```
104+
4. Check logs with
105+
```bash
106+
make logs
107+
```

requirements.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -118,5 +118,7 @@ eradicate==2.1.0
118118
mypy==1.0.0
119119
mypy-extensions==1.0.0
120120
vulture==2.7
121+
google-api-python-client==2.78.0
122+
google-auth-httplib2==0.1.0
121123
django-cid==2.3
122-
flake8==6.0.0
124+
flake8==6.0.0

scripts/clone_access_modules.py

+41-19
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,64 @@
88
f = open("./config.json", "r")
99
config = json.load(f)
1010
urls = config["access_modules"]["git_urls"]
11+
12+
requirements_file = 'Access/access_modules/requirements.txt'
13+
if not os.path.exists(requirements_file):
14+
open(requirements_file, 'w').close()
15+
1116
for url in urls:
1217
folder_name = url.split("/").pop()[:-4]
1318
folder_path = "./Access/access_modules/" + folder_name
1419
try:
15-
if os.path.exists(folder_path):
16-
Repo(folder_path).remotes.origin.pull()
17-
else:
18-
Repo.clone_from(url, folder_path)
19-
# move all folders, not files in the cloned repo to the access_modules
20-
# folder except the .git, .github and secrets folder
21-
for file in os.listdir(folder_path):
22-
if (
20+
Repo.clone_from(url, folder_path)
21+
# move all folders, not files in the cloned repo to the access_modules
22+
# folder except the .git, .github and secrets folder
23+
for file in os.listdir(folder_path):
24+
if (
2325
os.path.isdir(folder_path + "/" + file)
2426
and file != ".git"
2527
and file != ".github"
2628
and file != "secrets"
27-
):
29+
) :
30+
try :
2831
os.rename(
2932
folder_path + "/" + file, "./Access/access_modules/" + file
3033
)
34+
except:
35+
print("File is already present.")
36+
37+
if(file == "requirements.txt"):
38+
current_requirements_file = folder_path + "/" + file
39+
#Read the requirements
40+
with open(requirements_file, 'r') as f1:
41+
requirements1 = f1.readlines()
3142

32-
# remove the cloned repo folder entirely with all its contents which
33-
# includes folders and files using shutil.rmtree()
34-
# shutil.rmtree() sometimes throws an error on windows,
35-
# so we use try and except to ignore the error
36-
try:
37-
shutil.rmtree(folder_path)
38-
except Exception as e:
39-
print(e)
40-
print("failed to remove " + folder_path + " folder.")
43+
with open(current_requirements_file, 'r') as f1:
44+
requirements2 = f1.readlines()
4145

46+
# Merge the requirements
47+
merged_requirements = list(set(requirements1 + requirements2))
48+
49+
#update the requirements.txt
50+
with open(requirements_file, 'w') as out_file:
51+
for requirement in sorted(merged_requirements):
52+
out_file.write(requirement)
53+
4254
print("Cloning successful!")
55+
except Exception as e:
56+
print("error-->",e)
57+
print("failed cloning " + folder_name + ".")
4358

59+
# remove the cloned repo folder entirely with all its contents which
60+
# includes folders and files using shutil.rmtree()
61+
# shutil.rmtree() sometimes throws an error on windows,
62+
# so we use try and except to ignore the error
63+
try:
64+
shutil.rmtree(folder_path)
4465
except Exception as e:
4566
print(e)
46-
print("failed cloning " + folder_name + ".")
67+
print("failed to remove " + folder_path + " folder.")
68+
4769
except Exception as e:
4870
print("Access module cloning failed!")
4971
print(str(e))

secrets/ops_app_celery.env

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CELERY_BROKER_URL=redis://redis:6379/0
2+
CELERY_RESULT_BACKEND=redis://redis:6379/0
3+
C_FORCE_ROOT=true
4+
MYSQL_ROOT_PASSWORD=testtest
5+
MYSQL_DATABASE=enigma
6+
MYSQL_ROOT_HOST=%

0 commit comments

Comments
 (0)