Skip to content

Commit

Permalink
small bug fixes and organization
Browse files Browse the repository at this point in the history
  • Loading branch information
juls0730 committed Dec 9, 2024
1 parent 54fbb02 commit 6c035fc
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 289 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
fluxd
flux
!cmd/flux
!cmd/fluxd
fluxdd/
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,22 @@ Flux is a lightweight self-hosted pseudo-paas for golang web apps that emphasize
## Usage

To get started you'll want [ZQDGR](https://github.com/juls0730/zqdgr), and you can start the daemon either with:

```
zqdgr build:daemon
sudo ./fluxd
```
or with

or with

```
FLUXD_ROOT_DIR=$PWD/fluxdd zqdgr run:daemon
```

To get started with the cli you can run either
```
zqdgr build:cli
./flux list
```
or
To get started with the cli you can run

```
zqdgr run:cli -- list
go install github.com/juls0730/flux/cmd/flux@latest
```

TODO: `go install` instructions and a docker image (sowwy)
Expand Down Expand Up @@ -76,7 +75,9 @@ flux.json is the configuration file for a project, it contains the name of the p
- [Docker](https://docs.docker.com/get-docker/) (daemon only)

## Contributing

Found a bug, or have something you think would make Flux better? Submit an issue or pull request.

## License

Flux is licensed with the MIT license
File renamed without changes.
2 changes: 1 addition & 1 deletion cmd/cli/main.go → cmd/flux/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"time"

"github.com/briandowns/spinner"
"github.com/juls0730/fluxd/pkg"
"github.com/juls0730/flux/pkg"
)

//go:embed config.json
Expand Down
2 changes: 1 addition & 1 deletion cmd/daemon/main.go → cmd/fluxd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"net/http"
_ "net/http/pprof"

"github.com/juls0730/fluxd/server"
"github.com/juls0730/flux/server"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/juls0730/fluxd
module github.com/juls0730/flux

go 1.23.3

Expand Down
239 changes: 239 additions & 0 deletions server/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
package server

import (
"context"
"database/sql"
"fmt"
"log"
"os"
"path/filepath"
"sync"

"github.com/juls0730/flux/pkg"
)

type App struct {
ID int64 `json:"id,omitempty"`
Deployment Deployment `json:"-"`
Name string `json:"name,omitempty"`
DeploymentID int64 `json:"deployment_id,omitempty"`
}

func CreateApp(ctx context.Context, imageName string, projectPath string, projectConfig pkg.ProjectConfig) (*App, error) {
app := &App{
Name: projectConfig.Name,
}
log.Printf("Creating deployment %s...\n", app.Name)

container, err := CreateDockerContainer(ctx, imageName, projectPath, projectConfig)
if err != nil || container == nil {

return nil, fmt.Errorf("Failed to create container: %v", err)
}

deployment, err := CreateDeployment(*container, projectConfig.Port, projectConfig.Url, Flux.db)
app.Deployment = deployment
if err != nil {
log.Printf("Failed to create deployment: %v", err)
return nil, err
}

if appInsertStmt == nil {
appInsertStmt, err = Flux.db.Prepare("INSERT INTO apps (name, deployment_id) VALUES ($1, $2) RETURNING id, name, deployment_id")
if err != nil {
return nil, fmt.Errorf("Failed to prepare statement: %v", err)
}
}

// create app in the database
err = appInsertStmt.QueryRow(projectConfig.Name, deployment.ID).Scan(&app.ID, &app.Name, &app.DeploymentID)
if err != nil {
return nil, fmt.Errorf("Failed to insert app: %v", err)
}

err = deployment.Start(ctx)
if err != nil {
return nil, fmt.Errorf("Failed to start deployment: %v", err)
}

var headContainer *Container
for _, container := range deployment.Containers {
if container.Head {
headContainer = &container
}
}

deployment.Proxy, err = NewDeploymentProxy(&deployment, headContainer)
if err != nil {
return nil, fmt.Errorf("Failed to create deployment proxy: %v", err)
}

Flux.proxy.AddDeployment(&deployment)

Flux.appManager.AddApp(app.Name, app)

return app, nil
}

func (app *App) Upgrade(ctx context.Context, projectConfig pkg.ProjectConfig, imageName string, projectPath string) error {
log.Printf("Upgrading deployment %s...\n", app.Name)

// if deploy is not started, start it
deploymentStatus, err := app.Deployment.Status(ctx)
if deploymentStatus != "running" || err != nil {
err = app.Deployment.Start(ctx)
if err != nil {
return fmt.Errorf("Failed to start deployment: %v", err)
}
}

err = app.Deployment.Upgrade(ctx, projectConfig, imageName, projectPath)
if err != nil {
return fmt.Errorf("Failed to upgrade deployment: %v", err)
}

return nil
}

func (app *App) Remove(ctx context.Context) error {
err := app.Deployment.Remove(ctx)
if err != nil {
log.Printf("Failed to remove deployment: %v\n", err)
return err
}

_, err = Flux.db.Exec("DELETE FROM apps WHERE id = ?", app.ID)
if err != nil {
log.Printf("Failed to delete app: %v\n", err)
return err
}

projectPath := filepath.Join(Flux.rootDir, "apps", app.Name)
err = os.RemoveAll(projectPath)
if err != nil {
return fmt.Errorf("Failed to remove project directory: %v", err)
}

return nil
}

type AppManager struct {
sync.Map
}

func (am *AppManager) GetApp(name string) *App {
app, exists := am.Load(name)
if !exists {
return nil
}

return app.(*App)
}

func (am *AppManager) GetAllApps() []*App {
var apps []*App
am.Range(func(key, value interface{}) bool {
if app, ok := value.(*App); ok {
apps = append(apps, app)
}
return true
})
return apps
}

func (am *AppManager) AddApp(name string, app *App) {
am.Store(name, app)
}

func (am *AppManager) DeleteApp(name string) error {
app := am.GetApp(name)
if app == nil {
return fmt.Errorf("App not found")
}

err := app.Remove(context.Background())
if err != nil {
return err
}

am.Delete(name)

return nil
}

func (am *AppManager) Init(db *sql.DB) {
log.Printf("Initializing deployments...\n")

if db == nil {
log.Panicf("DB is nil")
}

rows, err := db.Query("SELECT id, name, deployment_id FROM apps")
if err != nil {
log.Printf("Failed to query apps: %v\n", err)
return
}
defer rows.Close()

var apps []App
for rows.Next() {
var app App
if err := rows.Scan(&app.ID, &app.Name, &app.DeploymentID); err != nil {
log.Printf("Failed to scan app: %v\n", err)
return
}
apps = append(apps, app)
}

for _, app := range apps {
var deployment Deployment
var headContainer *Container
db.QueryRow("SELECT id, url, port FROM deployments WHERE id = ?", app.DeploymentID).Scan(&deployment.ID, &deployment.URL, &deployment.Port)
deployment.Containers = make([]Container, 0)

rows, err = db.Query("SELECT id, container_id, deployment_id, head FROM containers WHERE deployment_id = ?", app.DeploymentID)
if err != nil {
log.Printf("Failed to query containers: %v\n", err)
return
}
defer rows.Close()

for rows.Next() {
var container Container
var containerIDString string
rows.Scan(&container.ID, &containerIDString, &container.DeploymentID, &container.Head)
container.Deployment = &deployment
copy(container.ContainerID[:], containerIDString)

if container.Head {
headContainer = &container
}

deployment.Containers = append(deployment.Containers, container)
}

for i, container := range deployment.Containers {
var volumes []Volume
rows, err := db.Query("SELECT id, volume_id, container_id FROM volumes WHERE container_id = ?", container.ID)
if err != nil {
log.Printf("Failed to query volumes: %v\n", err)
return
}
defer rows.Close()

for rows.Next() {
var volume Volume
rows.Scan(&volume.ID, &volume.VolumeID, &volume.ContainerID)
volumes = append(volumes, volume)
}

deployment.Containers[i].Volumes = volumes
}

deployment.Proxy, _ = NewDeploymentProxy(&deployment, headContainer)

app.Deployment = deployment

am.AddApp(app.Name, &app)
}
}
15 changes: 12 additions & 3 deletions server/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
"github.com/joho/godotenv"
"github.com/juls0730/fluxd/pkg"
"github.com/juls0730/flux/pkg"
)

var dockerClient *client.Client
Expand Down Expand Up @@ -45,7 +45,7 @@ func init() {
}
}

func CreateVolume(ctx context.Context, name string) (vol *Volume, err error) {
func CreateDockerVolume(ctx context.Context, name string) (vol *Volume, err error) {
dockerVolume, err := dockerClient.VolumeCreate(ctx, volume.CreateOptions{
Driver: "local",
DriverOpts: map[string]string{},
Expand Down Expand Up @@ -86,7 +86,7 @@ func CreateDockerContainer(ctx context.Context, imageName, projectPath string, p
}
}

vol, err := CreateVolume(ctx, fmt.Sprintf("flux_%s-volume", projectConfig.Name))
vol, err := CreateDockerVolume(ctx, fmt.Sprintf("flux_%s-volume", projectConfig.Name))

log.Printf("Creating container %s...\n", containerName)
resp, err := dockerClient.ContainerCreate(ctx, &container.Config{
Expand Down Expand Up @@ -177,6 +177,15 @@ func (c *Container) Wait(ctx context.Context, port uint16) error {
return WaitForDockerContainer(ctx, string(c.ContainerID[:]), port)
}

func (c *Container) Status(ctx context.Context) (string, error) {
containerJSON, err := dockerClient.ContainerInspect(ctx, string(c.ContainerID[:]))
if err != nil {
return "", err
}

return containerJSON.State.Status, nil
}

// RemoveContainer stops and removes a container, but be warned that this will not remove the container from the database
func RemoveDockerContainer(ctx context.Context, containerID string) error {
if err := dockerClient.ContainerStop(ctx, containerID, container.StopOptions{}); err != nil {
Expand Down
Loading

0 comments on commit 6c035fc

Please sign in to comment.