diff --git a/fe/app/api/route.ts b/fe/app/api/route.ts deleted file mode 100644 index b967ed7..0000000 --- a/fe/app/api/route.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { NextApiRequest, NextApiResponse } from 'next'; -import { config } from 'dotenv'; -import { Pool } from 'pg'; - -config({ path: '../../../.env.postgres' }); - -const pool = new Pool({ - host: 'localhost', - port: 5432, - user: process.env.POSTGRES_USER||"postgres", - password: process.env.POSTGRES_PASSWORD||"Welcome", - database: process.env.POSTGRES_DB||"postgres", - ssl: false, -}); - -export async function GET(req: NextApiRequest): Promise { - var slug=req.url?.toString().split("slug")[1] - slug=slug?.split("=")[1] - console.log("slug: ", slug) - console.log("pool: ", pool) - - - try { - const query = 'SELECT "loadbalancerDNS" FROM "Service" WHERE "slug" = $1'; - const result = await pool.query(query, [slug]); - - if (result.rows.length === 0) { - return new Response(JSON.stringify({ error: 'No service URL found for slug' }), - { status: 404, headers: { 'Content-Type': 'application/json' } }); - } - console.log("result dns of getlbdns: ", result) - return new Response(JSON.stringify( { lbDns: result.rows[0].loadbalancerDNS }), - { status: 200, headers: { 'Content-Type': 'application/json' } }); - - } catch (error) { - console.error('Error querying database:', error); - return new Response(JSON.stringify({ error: 'Internal server error' }), - { status: 500, headers: { 'Content-Type': 'application/json' } }); - - } -} \ No newline at end of file diff --git a/fe/app/service/page.tsx b/fe/app/service/page.tsx index 55fa3ac..c3b45e0 100644 --- a/fe/app/service/page.tsx +++ b/fe/app/service/page.tsx @@ -5,6 +5,7 @@ import { TabButton, ActiveTaskButton } from "@/components/TabButton"; import CreateService from '@/components/CreateService'; import Services from '@/components/Services'; import {Service} from '@/types'; +import ServiceForm from '@/components/ServiceForm'; export default function ServicePage() { const [activeService, setActiveService] = useState('create-deployment'); @@ -96,9 +97,9 @@ export default function ServicePage() {
- +
- +
diff --git a/fe/components/CreateService.tsx b/fe/components/CreateService.tsx index 9e04954..0ccece8 100644 --- a/fe/components/CreateService.tsx +++ b/fe/components/CreateService.tsx @@ -1,4 +1,5 @@ "use client" +import { Dispatch, SetStateAction } from "react"; import Earth3D from "./Earth3D"; import ServiceForm from "./ServiceForm"; @@ -6,7 +7,7 @@ export default function CreateService() { return (
- + {/* */}
) diff --git a/fe/components/ServiceForm.tsx b/fe/components/ServiceForm.tsx index 8fe8f28..f645835 100644 --- a/fe/components/ServiceForm.tsx +++ b/fe/components/ServiceForm.tsx @@ -1,14 +1,12 @@ -import React, { useState } from 'react'; import { Heading } from './Heading'; -import { Field } from './Field'; -import Image from 'next/image'; -import exclamationImg from '@/public/exclamation.png' -import { Env } from '@/types'; -import { time } from 'console'; +import { Env, Service } from '@/types'; import { uniqueNamesGenerator, Config, adjectives, animals } from 'unique-names-generator'; -const ServiceForm = () => { +import React, { Dispatch, SetStateAction } from 'react'; +import { useState } from 'react'; +const ServiceForm = ({services, setServices, setActiveService}:{services: Service[], + setServices: Dispatch>, setActiveService:Dispatch>}) => { const customConfig: Config = { dictionaries: [adjectives, animals], @@ -25,7 +23,7 @@ const ServiceForm = () => { const [error, setError] = useState(''); // const [env, setEnv] = useState(Env); // const [region, setRegion] = useState('US East (Ohio)'); - + const handleSubmit = (e:any) => { (async () => { // Handle form submission logic here @@ -45,7 +43,30 @@ const ServiceForm = () => { 'deploymentName': deploymentName, }), }); - console.log(resp.text()); + setIsLoading(false); + if (resp.ok) { + // Redirect to the service page + console.log(resp) + + const data = await resp.json(); + console.log(data); + setServices([...services, data]); + const scrollToService = (serviceName: string) => { + setActiveService(serviceName); + // can do better prop drilling + localStorage.setItem('activeService', serviceName); + const element = document.getElementById(serviceName); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + }; + scrollToService(data.name); + } else { + const data = await resp.json(); + setIsLoading(false); + setError(data.message); + + } })(); } diff --git a/fe/components/Services.tsx b/fe/components/Services.tsx index 5b9790b..1e8854a 100644 --- a/fe/components/Services.tsx +++ b/fe/components/Services.tsx @@ -1,67 +1,81 @@ import { Service } from "@/types"; import { Heading } from "./Heading"; -import { useState } from "react"; -export default function Services({ services }: { services: Service[] }) { +import { Dispatch, SetStateAction, useState } from "react"; +export default function Services({ services, setActiveService }: { services: Service[], setActiveService: Dispatch> }) { console.log("services from services maping component: ", services); const HOST_PROXY = process.env.HOST_PROXY || "localhost:80"; const [isLoading, setIsLoading] = useState(false); + const [isDeleted, setIsDeleted] = useState(false); return ( <> - + {services.map((service) => ( + service.createdAt && localStorage.setItem(service.slug, service.createdAt.toString()),
-
- - - - - -

{service.loadbalancerDNS}

- - - - - - - +
- await fetch(`http://localhost:3001/v1/delete-container/`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - "Authorization": "Bearer " + localStorage.getItem("token"), - }, - body: JSON.stringify({ - "image" :service.image, - "userName": service.userName, - }), - } - ) - setIsLoading(false) - window.location.reload() - } - }>{ - isLoading ? "Deleting..." : "Delete" - } - - -
))} diff --git a/fe/middleware.ts b/fe/middleware.ts index 65409e6..21f6689 100644 --- a/fe/middleware.ts +++ b/fe/middleware.ts @@ -15,7 +15,7 @@ export async function middleware(request: NextRequest) { const response = await fetch(apiUrl); if (response.ok) { const data = await response.json(); - url.hostname = data.lbDns; + url.hostname = data.dns; url.pathname = paths.slice(3).join('/'); url.port = '' console.info(`Redirecting to: ${url.toString()}`); diff --git a/pkg/controllers/deploy-container.go b/pkg/controllers/deploy-container.go index ea37ff2..8410c82 100644 --- a/pkg/controllers/deploy-container.go +++ b/pkg/controllers/deploy-container.go @@ -12,7 +12,6 @@ import ( "github.com/g4ze/byoc/pkg/core" byocTypes "github.com/g4ze/byoc/pkg/types" "github.com/joho/godotenv" - "github.com/sio/coolname" ) // Deploy the container @@ -62,16 +61,9 @@ func Deploy_container(newDeployment *byocTypes.DeployContainerPayload) (*byocTyp return nil, nil } - service.Slug, err = GenerateSlug(newDeployment.UserName) - if err != nil { - return nil, err - } + service.Slug = (newDeployment.DeploymentName) + log.Printf("returning service: %+v", service) return service, nil } -func GenerateSlug(UserName string) (string, error) { - slug, err := coolname.SlugN(3) - slug += "-" + UserName - return slug, err -} diff --git a/pkg/core/core_test.go b/pkg/core/core_test.go index 39269b8..5f49f89 100644 --- a/pkg/core/core_test.go +++ b/pkg/core/core_test.go @@ -109,7 +109,7 @@ func TestService(t *testing.T) { CreateTaskDefinition(svc, "test", img, 80, nil) log.Printf("Creating service") - service, err := CreateService(svc, elbSvc, "test", img, int32(80), []types.KeyValuePair{{Name: aws.String("test"), Value: aws.String("test")}}) + service, err := CreateService(svc, elbSvc, "test", img, int32(80), []types.KeyValuePair{{Name: aws.String("test"), Value: aws.String("test")}}, "test") if err != nil { log.Fatalf("Error creating service: %v", err) } diff --git a/pkg/core/service-ops.go b/pkg/core/service-ops.go index f17ad37..57a0dea 100644 --- a/pkg/core/service-ops.go +++ b/pkg/core/service-ops.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -16,7 +17,7 @@ import ( func CreateService(svc *ecs.Client, elbSvc *elbv2.ELBV2, UserName string, Image string, Port int32, Environment []types.KeyValuePair, DeploymentName string) (*byocTypes.Service, error) { var desiredCount int32 = 2 containerName := generateName(UserName, Image, "container") - serviceName := generateNameFromImage(Image) + serviceName := strings.ReplaceAll(DeploymentName, " ", "-") Family := generateName(UserName, Image, "task") isService, serviceStatus, err := ServiceExists(svc, serviceName, UserName) if err != nil { @@ -56,12 +57,12 @@ func CreateService(svc *ecs.Client, elbSvc *elbv2.ELBV2, UserName string, Image } log.Printf("Creating service %s", serviceName) // this needs a change, we cant keep creating load balancers - // based on the image name, we need to create a unique name - loadBalancerArn, lbdns, err := CreateLoadBalancer(elbSvc, Image) + // based on the service/deploymeny name, we need to create a unique name + loadBalancerArn, lbdns, err := CreateLoadBalancer(elbSvc, serviceName) if err != nil { return nil, fmt.Errorf("failed to create load balancer: %+v", err) } - targetGroupArn, err := CreateTargetGroup(elbSvc, Image) + targetGroupArn, err := CreateTargetGroup(elbSvc, serviceName) if err != nil { return nil, fmt.Errorf("failed to create target group: %v", err) } diff --git a/pkg/core/target-group-ops.go b/pkg/core/target-group-ops.go index 1a1ffe0..70d4797 100644 --- a/pkg/core/target-group-ops.go +++ b/pkg/core/target-group-ops.go @@ -9,8 +9,8 @@ import ( "github.com/aws/aws-sdk-go/service/elbv2" ) -func CreateTargetGroup(elbSvc *elbv2.ELBV2, Image string) (*string, error) { - targetGroupName := generateName("", Image, "tg") +func CreateTargetGroup(elbSvc *elbv2.ELBV2, deploymentName string) (*string, error) { + targetGroupName := generateName("", deploymentName, "tg") // Define target group input createInput := &elbv2.CreateTargetGroupInput{ diff --git a/pkg/database/reverse-proxy-call.go b/pkg/database/reverse-proxy-call.go index 5e9155c..7c82163 100644 --- a/pkg/database/reverse-proxy-call.go +++ b/pkg/database/reverse-proxy-call.go @@ -1,55 +1,35 @@ package database import ( + "context" "database/sql" - "fmt" - "os" + "log" - "github.com/joho/godotenv" + "github.com/g4ze/byoc/pkg/database/db" ) func GetLB_DNS(subdomain string) (string, error) { - // Connection parameters - err := godotenv.Load("../.env.postgres") - if err != nil { - return "", fmt.Errorf("error loading .env file: %v", err) - } - var ( - host = "localhost" - port = 5432 // Default PostgreSQL port - user = os.Getenv("POSTGRES_USER") - password = os.Getenv("POSTGRES_PASSWORD") - dbname = os.Getenv("POSTGRES_DB") - ) - - // Connection string - psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+ - "password=%s dbname=%s sslmode=disable", - host, port, user, password, dbname) - - // Open database connection - db, err := sql.Open("postgres", psqlInfo) - if err != nil { - return "", fmt.Errorf("error opening database connection: %v", err) + client := db.NewClient() + if err := client.Prisma.Connect(); err != nil { + return "", err } - defer db.Close() + defer func() { + if err := client.Prisma.Disconnect(); err != nil { + panic(err) + } + }() + ctx := context.Background() - // Test the connection - err = db.Ping() + resp, err := client.Service.FindMany( + db.Service.Slug.Equals(subdomain), + ).Exec(ctx) if err != nil { - return "", fmt.Errorf("error pinging database: %v", err) + return "", err } - - // Query the database - var serviceURL string - query := "SELECT \"loadbalancerDNS\" FROM \"Service\" WHERE \"slug\" = $1" - err = db.QueryRow(query, subdomain).Scan(&serviceURL) - if err != nil { - if err == sql.ErrNoRows { - return "", fmt.Errorf("no service URL found for subdomain: %s", subdomain) - } - return "", fmt.Errorf("error querying database: %v", err) + if len(resp) == 0 { + return "", sql.ErrNoRows } + log.Print("Got response: ", resp[0].LoadbalancerDNS) + return resp[0].LoadbalancerDNS, nil - return serviceURL, nil } diff --git a/pkg/handlers/getlbdns.go b/pkg/handlers/getlbdns.go index 0c39eda..868c732 100644 --- a/pkg/handlers/getlbdns.go +++ b/pkg/handlers/getlbdns.go @@ -3,6 +3,7 @@ package handlers import ( "log" + "github.com/g4ze/byoc/pkg/database" "github.com/gin-gonic/gin" ) @@ -17,6 +18,11 @@ func Get_LBDNS(c *gin.Context) { return } // get lb dns - GetLB_DNS(slug) + dns, err := database.GetLB_DNS(slug) + if err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + c.JSON(200, gin.H{"dns": dns, "slug": slug}) } diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 74a4a9f..c82d7d3 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -29,6 +29,7 @@ func Server() { // 429 = too many requests r.POST("/create-user", handlers.Create_User) r.POST("/login", handlers.Login) + r.GET("/get-lbdns", handlers.Get_LBDNS) // Create a new group for routes that require JWT middleware authRoutes.POST("/whoami", handlers.WhoAMI) authRoutes.POST("/make-cluster", handlers.Make_Cluster) @@ -37,5 +38,5 @@ func Server() { authRoutes.DELETE("/delete-container", handlers.Delete_Container) authRoutes.GET("/get-services", handlers.Get_Services) - r.Run(":2001") // listen and serve on 0.0.0.0:2001 + r.Run(":2001") }