Skip to content

Commit

Permalink
Local lint & Director CLI hookup + bug fixes
Browse files Browse the repository at this point in the history
PR #7 introduced a framework for including the Director in the Pelican CLI,
toward making all Pelican services available under a single binary. This commit
extends that PR to hook the Director package up to the CLI, the Pelican's
configuration mechanisms, and to actually sort out a few bugs related to the
untested director code.

It should be noted that there are currently a few hacks in the code that need
clearing up before any merge, but as of now the commit makes the following
possible:
`pelican director serve --cache-port 8000`
This will serve the Director's cache-redirection service on port 8000 using a gin
engine. When we've figured out how to handle Origin redirects and implemented an
origin-redirect service, we'll be able to do:
`pelican director serve --cache-port 8000 --origin-port 8001`
to split apart the two endpoints.

As for the local lint... I'm still trying to figure out how to shut that feature
off in my editor. Sorry for the noise!
  • Loading branch information
jhiemstrawisc committed Jul 21, 2023
1 parent 62a0dd3 commit bc56423
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 110 deletions.
52 changes: 52 additions & 0 deletions cmd/director.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright © 2023 Justin Hiemstra <jhiemstra@morgridge.org>
*/
package main

import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// directorCmd represents the director command
var (
directorCmd = &cobra.Command{
Use: "director",
Short: "Launch a Pelican Director",
Long: `Launch a Pelican Director service:
The Pelican Director is responsible for origin/cache discovery within
the Pelican Platform. When a client asks the Director how to obtain a
specific namespaced resource, the Director will respond with the info
needed by the client (usually a cache and some authentication details)
to obtain that information. When a cache asks the Director for the same
namespaced resource, the Director will point the cache to the origin
responsible for serving the object.`,
}

directorServeCmd = &cobra.Command{
Use: "serve",
Short: "serve the director service",
RunE: serveDirector,
SilenceUsage: true,
}
)

func init() {
// Tie the directorServe command to the root CLI command
directorCmd.AddCommand(directorServeCmd)

// Set up flags for the command
directorServeCmd.Flags().StringP("cache-port", "p", "", "Set the port to which the Director's cache redirect service should be bound")
err := viper.BindPFlag("cachePort", directorServeCmd.Flags().Lookup("cache-port"))
if err != nil {
panic(err)
}

directorServeCmd.Flags().StringP("origin-port", "P", "", "Set the port to which the Director's origin redirect service should be bound")
err = viper.BindPFlag("originPort", directorServeCmd.Flags().Lookup("origin-port"))
if err != nil {
panic(err)
}

}
33 changes: 33 additions & 0 deletions cmd/director_serve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"github.com/gin-gonic/gin"
"github.com/pelicanplatform/pelican/director"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func serveDirector( /*cmd*/ *cobra.Command /*args*/, []string) error {
log.Info("Initializing Director GeoIP database...")
director.InitializeDB()

log.Info("Generating/advertising server ads...")
director.AdvertiseOSDF()

gin.SetMode(gin.ReleaseMode)
cacheEngine := gin.Default()
director.RegisterDirector(cacheEngine.Group("/"))

// Eventually we'll want a redirect-to-origin service split off
// on another port. Can we use a groutine to handle that here?
cachePort := viper.GetString("cachePort")
//originPort := viper.GetString("originPort")
log.Info("Serving cache redirector on port", cachePort)
err := cacheEngine.Run(":" + cachePort)
if err != nil {
panic(err)
}

return nil
}
15 changes: 7 additions & 8 deletions cmd/origin.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

package main

import (
Expand All @@ -13,23 +12,23 @@ var (
originCmd = &cobra.Command{
Use: "origin",
Short: "Operate a Pelican origin service",
}
}

originConfigCmd = &cobra.Command{
Use: "config",
Use: "config",
Short: "Launch the Pelican web service in configuration mode",
Run: configOrigin,
Run: configOrigin,
}

originServeCmd = &cobra.Command{
Use: "serve",
Short: "Start the origin service",
RunE: serve,
Use: "serve",
Short: "Start the origin service",
RunE: serveOrigin,
SilenceUsage: true,
}
)

func configOrigin(/*cmd*/ *cobra.Command, /*args*/ []string) {
func configOrigin( /*cmd*/ *cobra.Command /*args*/, []string) {
fmt.Println("'origin config' command is not yet implemented")
os.Exit(1)
}
Expand Down
81 changes: 40 additions & 41 deletions cmd/origin_serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"math/big"
"net/http"
"os"
"os/exec"
"os/signal"
"math/big"
"net/http"
"path"
"path/filepath"
"strings"
Expand All @@ -28,12 +28,12 @@ import (

"github.com/gin-gonic/gin"
"github.com/lestrrat-go/jwx/jwk"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/pelicanplatform/pelican"
"github.com/pelicanplatform/pelican/config"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
Expand All @@ -52,27 +52,27 @@ var (
)

type XrootdConfig struct {
Port int
ManagerHost string
ManagerPort string
TLSCertificate string
TLSKey string
TLSCertDir string
TLSCertFile string
MacaroonsKeyFile string
RobotsTxtFile string
Sitename string
SummaryMonitoringHost string
SummaryMonitoringPort int
Port int
ManagerHost string
ManagerPort string
TLSCertificate string
TLSKey string
TLSCertDir string
TLSCertFile string
MacaroonsKeyFile string
RobotsTxtFile string
Sitename string
SummaryMonitoringHost string
SummaryMonitoringPort int
DetailedMonitoringHost string
DetailedMonitoringPort int
XrootdRun string
Authfile string
ScitokensConfig string
Mount string
NamespacePrefix string
XrootdMultiuser bool
LocalMonitoringPort int
XrootdRun string
Authfile string
ScitokensConfig string
Mount string
NamespacePrefix string
XrootdMultiuser bool
LocalMonitoringPort int
}

func cleanupDirOnShutdown(dir string) {
Expand Down Expand Up @@ -222,12 +222,12 @@ func generateCert() error {
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Pelican"},
CommonName: hostname,
CommonName: hostname,
},
NotBefore: notBefore,
NotAfter: notBefore.Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
NotBefore: notBefore,
NotAfter: notBefore.Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
}
template.DNSNames = []string{hostname}
Expand Down Expand Up @@ -288,7 +288,6 @@ func generatePrivateKey(keyLocation string) error {
keyLocation, groupname)
}


bytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return err
Expand Down Expand Up @@ -360,7 +359,7 @@ func checkXrootdEnv() error {
return errors.Wrapf(err, "Unable to create runtime directory %v", runtimeDir)
}
if err = os.Chown(runtimeDir, uid, -1); err != nil {
return errors.Wrapf(err, "Unable to change ownership of runtime directory %v" +
return errors.Wrapf(err, "Unable to change ownership of runtime directory %v"+
" to desired daemon user %v", runtimeDir, username)
}

Expand Down Expand Up @@ -515,7 +514,7 @@ to export the directory /mnt/foo to the path /bar in the data federation`)
}
}
if err = os.Chown(macaroonsSecret, -1, gid); err != nil {
return errors.Wrapf(err, "Unable to change ownership of macaroons secret %v" +
return errors.Wrapf(err, "Unable to change ownership of macaroons secret %v"+
" to desired daemon group %v", macaroonsSecret, groupname)
}

Expand All @@ -532,7 +531,7 @@ to export the directory /mnt/foo to the path /bar in the data federation`)
return err
}
if err = os.Chown(authfile, -1, gid); err != nil {
return errors.Wrapf(err, "Unable to change ownership of authfile %v" +
return errors.Wrapf(err, "Unable to change ownership of authfile %v"+
" to desired daemon group %v", macaroonsSecret, groupname)
}

Expand All @@ -548,7 +547,7 @@ to export the directory /mnt/foo to the path /bar in the data federation`)
return err
}
if err = os.Chown(scitokensCfg, -1, gid); err != nil {
return errors.Wrapf(err, "Unable to change ownership of scitokens config %v" +
return errors.Wrapf(err, "Unable to change ownership of scitokens config %v"+
" to desired daemon group %v", scitokensCfg, groupname)
}

Expand All @@ -557,7 +556,7 @@ to export the directory /mnt/foo to the path /bar in the data federation`)

func checkConfigFileReadable(fileName string, errMsg string) error {
if _, err := os.Open(fileName); errors.Is(err, os.ErrNotExist) {
return errors.New(fmt.Sprintf("%v: the specified path in the configuration (%v) " +
return errors.New(fmt.Sprintf("%v: the specified path in the configuration (%v) "+
"does not exist", errMsg, fileName))
} else if err != nil {
return errors.New(fmt.Sprintf("%v; an error occurred when reading %v: %v", errMsg,
Expand Down Expand Up @@ -587,11 +586,11 @@ func checkDefaults() error {

// TODO: Could upgrade this to a check for a cert in the file...
if err := checkConfigFileReadable(viper.GetString("TLSCertificate"),
"A TLS certificate is required to serve HTTPS"); err != nil {
"A TLS certificate is required to serve HTTPS"); err != nil {
return err
}
if err := checkConfigFileReadable(viper.GetString("TLSKey"),
"A TLS key is required to serve HTTPS"); err != nil {
"A TLS key is required to serve HTTPS"); err != nil {
return err
}

Expand Down Expand Up @@ -730,8 +729,8 @@ func launchXrootd() error {
} else {
panic(errors.New("Unable to convert signal to syscall.Signal"))
}
xrootdExpiry = time.Now().Add(10*time.Second)
cmsdExpiry = time.Now().Add(10*time.Second)
xrootdExpiry = time.Now().Add(10 * time.Second)
cmsdExpiry = time.Now().Add(10 * time.Second)
case waitResult := <-xrootdDoneChannel:
if waitResult != nil {
if !cmsdExpiry.IsZero() {
Expand Down Expand Up @@ -763,12 +762,12 @@ func launchXrootd() error {
}
}

func serve(/*cmd*/ *cobra.Command, /*args*/ []string) error {
func serveOrigin( /*cmd*/ *cobra.Command /*args*/, []string) error {
defer func() {
if tempRunDir != "" {
os.RemoveAll(tempRunDir)
}
} ()
}()

monitorPort, err := pelican.ConfigureMonitoring()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/origin_serve_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import (
"github.com/spf13/cobra"
)

func serve(/*cmd*/ *cobra.Command, /*args*/ []string) error {
func serveOrigin( /*cmd*/ *cobra.Command /*args*/, []string) error {
return errors.New("'origin serve' command is not supported on Windows")
}
9 changes: 3 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/*
Copyright 2023 Brian Bockelman <bbockelman@morgridge.org>
*/
package main

Expand All @@ -15,9 +14,8 @@ import (
"github.com/spf13/viper"
)


var (
cfgFile string
cfgFile string
outputJSON bool

rootCmd = &cobra.Command{
Expand All @@ -38,11 +36,10 @@ func Execute() {

func init() {



cobra.OnInitialize(initConfig)

rootCmd.AddCommand(objectCmd)
rootCmd.AddCommand(directorCmd)
objectCmd.CompletionOptions.DisableDefaultCmd = true
rootCmd.AddCommand(originCmd)
rootCmd.AddCommand(rootConfigCmd)
Expand Down Expand Up @@ -73,7 +70,7 @@ func initConfig() {
viper.AddConfigPath(filepath.Join(home, ".config", "pelican"))
viper.AddConfigPath(filepath.Join("/etc", "pelican"))
viper.SetConfigType("yaml")
viper.SetConfigName("pelican.yaml")
viper.SetConfigName("pelican")
}
if err := viper.BindPFlag("Debug", rootCmd.Flags().Lookup("debug")); err != nil {
panic(err)
Expand Down
Loading

0 comments on commit bc56423

Please sign in to comment.