diff --git a/.gitea/workflows/build-and-push.yaml b/.gitea/workflows/build-and-push.yaml index 3db58d9..b29285e 100644 --- a/.gitea/workflows/build-and-push.yaml +++ b/.gitea/workflows/build-and-push.yaml @@ -2,8 +2,7 @@ -name: Build and Push to Private Registry - +name: Build and Push to Private Registry101 on: push: @@ -24,6 +23,15 @@ jobs: id: extract_branch - uses: actions/checkout@v3 - run: docker login kube-reg.fairfaxmedia.net -u docker -p ${{ secrets.DOCK_REG_AUTH }} # Login to private registry + name: Login to private registry - run: docker build -t kube-reg.fairfaxmedia.net/papi/svc1:${{ steps.extract_branch.outputs.branch }} . # Build the Docker image + name: Build Docker image - run: docker push kube-reg.fairfaxmedia.net/papi/svc1:${{ steps.extract_branch.outputs.branch }} # Push the Docker image + name: Push Docker image + #- env: + #KUBEB64: '${{ secrets.KUBEB64 }}' + #run: mkdir -p $HOME/.kube &&echo "$KUBEB64" | base64 -d > $HOME/.kube/config && + #curl https://fairfaxmedia.net/helm -o /usr/local/bin/helm && chmod +xxx /usr/local/bin/helm && + #/usr/local/bin/helm upgrade --install papi papi-helm/ --set image.tag=${{ steps.extract_branch.outputs.branch }} # Deploy the Helm chart + diff --git a/.gitignore b/.gitignore index 597be97..391f3a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ __pycache__ test.db +.coverage +report.xml +coverage.xml \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8b9a1f0 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +ENV=dev +VER=2 +TAG=${ENV}-${VER} +REGISTRY=kube-reg.fairfaxmedia.net +SVC=papi/svc1 +DOCK_IMG=${REGISTRY}/${SVC}:${TAG} +clean: + rm -rf .pytest_cache + rm -rf .coverage + rm -rf report.xml + rm -rf test.db +coverage: clean + pytest --cov=papi test_papi.py --junitxml=report.xml --cov-report=html --cov-report=xml --cov-report=term --cov-fail-under 90 +docker-img: coverage + docker build -t ${DOCK_IMG} . +docker-push: docker-img + docker push ${DOCK_IMG} +deploy: docker-push + helm upgrade papi ./papi-helm/ -f ./papi-helm/v.${ENV}.yaml --set image.tag=${TAG} \ No newline at end of file diff --git a/build.sh b/build.sh deleted file mode 100644 index 8f2d93b..0000000 --- a/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -REG=192.168.1.134:5000 -NS=papi -IMG=svc1 -TAG=dev -DIMG=${REG}/${NS}/${IMG}:${TAG} -docker build -f Dockerfile -t ${DIMG} . - -docker push ${DIMG} \ No newline at end of file diff --git a/deploy.dev.sh b/deploy.dev.sh new file mode 100644 index 0000000..1c4056c --- /dev/null +++ b/deploy.dev.sh @@ -0,0 +1,2 @@ +#!/bin/bash +helm upgrade papi ./papi-helm/ -f ./papi-helm/v.dev.yaml diff --git a/hopscotch_collection.json b/hopscotch_collection.json new file mode 100644 index 0000000..42c3ab5 --- /dev/null +++ b/hopscotch_collection.json @@ -0,0 +1 @@ +{"v":1,"name":"test_assignment","folders":[{"v":1,"name":"users","folders":[],"requests":[{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users","name":"list_users","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":null,"body":null}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users","name":"create_user","params":[],"headers":[],"method":"POST","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"test2\",\n \"email\":\"mynameisdeleted@gmail.com\",\n \"password\":\"pass2\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users/1","name":"update_user","params":[],"headers":[],"method":"PUT","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users/1","name":"delete_user","params":[],"headers":[],"method":"DELETE","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users/1","name":"get_user","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":null,"body":null}}]},{"v":1,"name":"posts","folders":[],"requests":[{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts","name":"list_posts","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts","name":"create_post","params":[],"headers":[],"method":"POST","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"title\":\"test title\",\n \"content\":\"testing123\",\n \"author_id\":\"1\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts/1","name":"get_post","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts/1","name":"update_post","params":[],"headers":[],"method":"PUT","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"title\":\"new title\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts/1","name":"delete_post","params":[],"headers":[],"method":"DELETE","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"title\":\"new title\"\n}"}}]}],"requests":[]} \ No newline at end of file diff --git a/papi-helm/v.dev.yaml b/papi-helm/v.dev.yaml new file mode 100644 index 0000000..bae8507 --- /dev/null +++ b/papi-helm/v.dev.yaml @@ -0,0 +1,7 @@ +ingress: + enabled: true + hosts: + - host: papi.kube-dev.fairfaxmedia.net + paths: + - path: / + pathType: ImplementationSpecific \ No newline at end of file diff --git a/papi-helm/v.prod.yaml b/papi-helm/v.prod.yaml new file mode 100644 index 0000000..e5a0d41 --- /dev/null +++ b/papi-helm/v.prod.yaml @@ -0,0 +1,11 @@ +ingress: + enabled: true + hosts: + - host: papi.fairfaxmedia.net + paths: + - path: / + pathType: ImplementationSpecific + - host: papi.kube.fairfaxmedia.net + paths: + - path: / + pathType: ImplementationSpecific \ No newline at end of file diff --git a/papi-helm/v.qa.yaml b/papi-helm/v.qa.yaml new file mode 100644 index 0000000..5c76701 --- /dev/null +++ b/papi-helm/v.qa.yaml @@ -0,0 +1,7 @@ +ingress: + enabled: true + hosts: + - host: papi.kube-qa.fairfaxmedia.net + paths: + - path: / + pathType: ImplementationSpecific \ No newline at end of file diff --git a/papi-helm/values.yaml b/papi-helm/values.yaml index 4213baf..ac886a9 100644 --- a/papi-helm/values.yaml +++ b/papi-helm/values.yaml @@ -52,7 +52,7 @@ securityContext: {} # This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ service: # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types - type: NodePort + type: ClusterIP # This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports port: 8912 @@ -63,16 +63,6 @@ ingress: annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" - hosts: - - host: papi.fairfaxmedia.net - paths: - - path: / - pathType: ImplementationSpecific - - - host: papi.kube-dev.fairfaxmedia.net - paths: - - path: / - pathType: ImplementationSpecific tls: [] # - secretName: chart-example-tls # hosts: diff --git a/papi.py b/papi.py index bda569c..4925f3c 100644 --- a/papi.py +++ b/papi.py @@ -2,9 +2,8 @@ from fastapi import FastAPI, Depends import uvicorn from sqlalchemy import create_engine, Column, Integer,String, ForeignKey -from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.engine import URL -from sqlalchemy.orm import sessionmaker, Session +from sqlalchemy.orm import sessionmaker, Session, declarative_base @@ -30,6 +29,7 @@ class User(Base): email = Column(String, unique=True, index=True) password = Column(String) + class Post(Base): __tablename__ = "posts" id = Column(Integer, primary_key=True, index=True) @@ -50,10 +50,11 @@ async def root(): @app.get("/users") async def get_users(db: Session = Depends(get_db)): return db.query(User).all() - #return [{"id":"asdf1234"}] + @app.get("/users/{id}") -async def get_user(id: str): - return {"id": id} +async def get_user(id: str,db: Session = Depends(get_db)): + db_user = db.query(User).filter(User.id == id).first() + return db_user @app.post("/users") async def create_user(user: dict,db: Session = Depends(get_db)): @@ -64,6 +65,30 @@ async def create_user(user: dict,db: Session = Depends(get_db)): db.refresh(db_user) return {"message":"User created successfully","user":db_user} +@app.put("/users/{id}") +async def update_user(id: str, user: dict,db: Session = Depends(get_db)): + db_user = db.query(User).filter(User.id == id).first() + if "name" in user: + db_user.name = user["name"] + if "email" in user: + db_user.email = user["email"] + if "password" in user: + db_user.password = user["password"] + db.commit() + db.refresh(db_user) + return {"message":"User updated successfully","user":db_user} + + + +@app.delete("/users/{id}") +async def delete_user(id: str, db: Session = Depends(get_db)): + db_user = db.query(User).filter(User.id == id).first() + db.delete(db_user) + db.commit() + return {"message":"User deleted successfully","user":db_user} + + + @app.get("/posts") async def get_posts(db: Session = Depends(get_db)): return db.query(Post).all() @@ -92,19 +117,14 @@ async def update_post(id: str, post: dict,db: Session = Depends(get_db)): db.refresh(db_post) return {"message":"Post updated successfully","post":db_post} -@app.delete("/posts/{id}",db: Session = Depends(get_db)) -async def delete_post(id: str, post: dict): +@app.delete("/posts/{id}") +async def delete_post(id: str, db: Session = Depends(get_db)): db_post = db.query(Post).filter(Post.id == id).first() db.delete(db_post) db.commit() return {"message":"Post deleted successfully","post":db_post} -@app.get("/hello/{name}") -async def say_hello(name: str): - return {"message": f"Hello {name}"} - - if __name__ == "__main__": uvicorn.run("papi:app", host="0.0.0.0", port=8912, reload=True, log_level="debug", diff --git a/test_papi.py b/test_papi.py new file mode 100644 index 0000000..3856a74 --- /dev/null +++ b/test_papi.py @@ -0,0 +1,79 @@ +#!/bin/env python3 + +from fastapi.testclient import TestClient + +from papi import app +client = TestClient(app) + + +def test_read_main(): + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"message": "Hello World"} + +def test_read_users(): + response = client.get("/users") + assert response.status_code == 200 + assert response.json() == [] + + +def test_create_read_delete_user(): + + response = client.post("/users",json={"name":"test","email":"mynameisdeleted@gmail.com","password":"pass2"}) + assert response.status_code == 200 + user=response.json()['user'] + user_id = str(user['id']) + response = client.get("/users/"+user_id) + assert response.status_code == 200 + assert response.json() == user + + update_response = client.put("/users/"+user_id,json={"name":"updated name"}) + #assert update_respose.status_code == 200 + put_user = update_response.json()['user'] + assert put_user['name'] == "updated name" + + update_response = client.put("/users/"+user_id,json={"email":"updated@gmail.com"}) + + put_user = update_response.json()['user'] + assert put_user['email'] == "updated@gmail.com" + + + response = client.delete("/users/"+user_id) + assert response.status_code == 200 + + response = client.get("/users") + assert response.status_code == 200 + assert response.json() == [] + + + + +def test_create_read_delete_post(): + + + response = client.post("/posts",json={"title":"test title","content":"testing123","author_id":"1"}) + assert response.status_code == 200 + post=response.json()['post'] + post_id = str(post['id']) + response = client.get("/posts/"+post_id) + assert response.status_code == 200 + assert response.json() == post + + update_response = client.put("/posts/"+post_id,json={"title":"test title updated"}) + #assert update_respose.status_code == 200 + put_post = update_response.json()['post'] + assert put_post['title'] == "test title updated" + + + update_response = client.put("/posts/"+post_id,json={"content":"updated content"}) + #assert update_respose.status_code == 200 + put_post = update_response.json()['post'] + assert put_post['title'] == "test title updated" + assert put_post['content'] == "updated content" + + response = client.delete("/posts/"+post_id) + assert response.status_code == 200 + + response = client.get("/posts") + assert response.status_code == 200 + assert response.json() == [] \ No newline at end of file