Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add caddy server as system install #1070

Merged
merged 2 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ Run the following to see what's available `arkade system install`:
```
actions-runner Install GitHub Actions Runner
buildkitd Install Buildkitd
caddy Install Caddy Server
cni Install CNI plugins
containerd Install containerd
firecracker Install Firecracker
Expand Down
171 changes: 171 additions & 0 deletions cmd/system/caddy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright (c) arkade author(s) 2024. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package system

import (
"context"
"errors"
"fmt"
"os"
"os/user"
"strings"

"github.com/alexellis/arkade/pkg/env"
"github.com/alexellis/arkade/pkg/get"
execute "github.com/alexellis/go-execute/v2"
"github.com/spf13/cobra"
)

func MakeInstallCaddyServer() *cobra.Command {
command := &cobra.Command{
Use: "caddy",
Short: "Install Caddy Server",
Long: `Install Caddy Server which is an extensible server platform that uses TLS by default`,
Example: ` arkade system install caddy
arkade system install caddy --version <version>`,
SilenceUsage: true,
}

command.Flags().StringP("version", "v", "", "The version or leave blank to determine the latest available version")
command.Flags().String("path", "/usr/bin", "Installation path, where a caddy subfolder will be created")
command.Flags().Bool("progress", true, "Show download progress")
command.Flags().String("arch", "", "CPU architecture i.e. amd64")

command.PreRunE = func(cmd *cobra.Command, args []string) error {
return nil
}

command.RunE = func(cmd *cobra.Command, args []string) error {
installPath, _ := cmd.Flags().GetString("path")
version, _ := cmd.Flags().GetString("version")
progress, _ := cmd.Flags().GetBool("progress")

arch, osVer := env.GetClientArch()

if strings.ToLower(osVer) != "linux" {
return fmt.Errorf("this app only supports Linux")
}

tools := get.MakeTools()
Copy link
Owner

@alexellis alexellis Jun 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change mean that "caddy" also appears via arkade get caddy?

In the case of things like Go or Node, we won't that because it won't do the right thing. We could have an additional flag or bool etc on each Tool to hide them from the arkade get command

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. will start working toward migrating system apps to use this new approach and enable apps which we want as system install only

var tool *get.Tool
for _, t := range tools {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach. Could you create an issue to retrofit this into the existing system install apps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I would try to progressively apply this approach in system install apps.

if t.Name == "caddy" {
tool = &t
break
}
}

if tool == nil {
return fmt.Errorf("unable to find caddy definition")
}

fmt.Printf("Installing Caddy Server to %s\n", installPath)

installPath = strings.ReplaceAll(installPath, "$HOME", os.Getenv("HOME"))

if err := os.MkdirAll(installPath, 0755); err != nil && !os.IsExist(err) {
fmt.Printf("Error creating directory %s, error: %s\n", installPath, err.Error())
}

if version == "" {
v, err := get.FindGitHubRelease("caddyserver", "caddy")
if err != nil {
return err
}
version = v
} else if !strings.HasPrefix(version, "v") {
version = "v" + version
}

outFilePath, _, err := get.Download(tool, arch, osVer, version, installPath, progress, !progress)
if err != nil {
return err
}
if err = os.Chmod(outFilePath, readWriteExecuteEveryone); err != nil {
return err
}

svcTmpPath, err := get.DownloadFileP("https://raw.githubusercontent.com/caddyserver/dist/master/init/caddy.service", false)
if err != nil {
return err
}
fmt.Printf("Downloaded caddy.service file to %s\n", svcTmpPath)
defer os.Remove(svcTmpPath)

caddySystemFile := "/etc/systemd/system/caddy.service"
if _, err = get.CopyFile(svcTmpPath, caddySystemFile); err != nil {
return err
}
fmt.Printf("Copied caddy.service file to %s\n", caddySystemFile)

caddyHomeDir := "/var/lib/caddy"
caddyConfDir := "/etc/caddy"
caddyUser := "caddy"
if err = createCaddyConf(caddyHomeDir, caddyConfDir); err != nil {
return err
}
fmt.Printf("Created caddy home %s and Conf %s directory\n", caddyHomeDir, caddyConfDir)

if _, err = user.Lookup(caddyUser); errors.Is(err, user.UnknownUserError(caddyUser)) {
if _, err = executeShellCmd(context.Background(), "useradd", "--system", "--home", caddyHomeDir, "--shell", "/bin/false", caddyUser); err != nil {
return err
}
fmt.Printf("User created for caddy server.\n")
}

if _, err = executeShellCmd(context.Background(), "chown", "--recursive", "caddy:caddy", "/var/lib/caddy"); err != nil {
return err
}

if _, err = executeShellCmd(context.Background(), "chown", "--recursive", "caddy:caddy", "/etc/caddy"); err != nil {
return err
}

if _, err = executeShellCmd(context.Background(), "systemctl", "enable", "caddy"); err != nil {
return err
}

if _, err = executeShellCmd(context.Background(), "systemctl", "daemon-reload"); err != nil {
return err
}

return nil
}

return command
}

func createCaddyConf(caddyHomeDir, caddyConfDir string) error {
os.MkdirAll(caddyHomeDir, 0755)
os.MkdirAll(caddyConfDir, 0755)

caddyConfFilePath := fmt.Sprintf("%s/Caddyfile", caddyConfDir)
caddyFile, err := os.Create(caddyConfFilePath)
if err != nil {
return err
}
defer caddyFile.Close()
return nil
}

func executeShellCmd(ctx context.Context, cmd string, parts ...string) (execute.ExecResult, error) {
task := execute.ExecTask{
Command: cmd,
Args: parts,
Env: os.Environ(),
StreamStdio: true,
}

res, err := task.Execute(ctx)

if err != nil {
return res, err
}

if res.ExitCode != 0 {
return res, fmt.Errorf("exit code %d, stderr: %s", res.ExitCode, res.Stderr)
}

return res, nil
}
1 change: 1 addition & 0 deletions cmd/system/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func MakeInstall() *cobra.Command {
command.AddCommand(MakeInstallGitLabRunner())
command.AddCommand((MakeInstallBuildkitd()))
command.AddCommand(MakeInstallPowershell())
command.AddCommand(MakeInstallCaddyServer())

return command
}
Loading