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

Log/command #132

Merged
merged 3 commits into from
Sep 13, 2020
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
48 changes: 7 additions & 41 deletions alias/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ import (
"time"

"github.com/BurntSushi/toml"
"github.com/davrodpin/mole/fsutils"
)

const (
InstancePidFile = "pid"
InstanceLogFile = "mole.log"
ShowTemplate = `{{.Name}}
ShowTemplate = `{{.Name}}
verbose: {{.Verbose}}
insecure: {{.Insecure}}
detach: {{.Detach}}
Expand Down Expand Up @@ -213,27 +212,6 @@ func (a Alias) String() string {
)
}

type InstanceConfiguration struct {
Home string
LogFile string
PidFile string
}

func NewInstanceConfiguration(aliasName string) (*InstanceConfiguration, error) {
aliasDir, err := Dir()
if err != nil {
return nil, err
}

home := filepath.Join(aliasDir, aliasName)

return &InstanceConfiguration{
Home: home,
LogFile: filepath.Join(home, InstanceLogFile),
PidFile: filepath.Join(home, InstancePidFile),
}, nil
}

// Add persists an tunnel alias to the disk
func Add(alias *Alias) error {
mp, err := createDir()
Expand All @@ -260,7 +238,7 @@ func Add(alias *Alias) error {

// Delete destroys a alias configuration file.
func Delete(alias string) error {
mp, err := Dir()
mp, err := fsutils.Dir()

if err != nil {
return err
Expand All @@ -282,7 +260,7 @@ func Delete(alias string) error {

// Show displays the configuration parameters for the given alias name.
func Show(aliasName string) (string, error) {
mp, err := Dir()
mp, err := fsutils.Dir()
if err != nil {
return "", err
}
Expand All @@ -294,7 +272,7 @@ func Show(aliasName string) (string, error) {

// ShowAll displays the configuration parameters for all persisted aliases.
func ShowAll() (string, error) {
mp, err := Dir()
mp, err := fsutils.Dir()
if err != nil {
return "", err
}
Expand Down Expand Up @@ -324,7 +302,7 @@ func ShowAll() (string, error) {

// Get returns an alias previously created
func Get(aliasName string) (*Alias, error) {
mp, err := Dir()
mp, err := fsutils.Dir()
if err != nil {
return nil, err
}
Expand All @@ -344,18 +322,6 @@ func Get(aliasName string) (*Alias, error) {
return a, nil
}

// Dir returns directory path where all alias files are stored.
func Dir() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}

mp := filepath.Join(home, ".mole")

return mp, nil
}

func showAlias(filePath string) (string, error) {
an := strings.TrimSuffix(filepath.Base(filePath), ".toml")

Expand All @@ -379,7 +345,7 @@ func showAlias(filePath string) (string, error) {
}

func createDir() (string, error) {
mp, err := Dir()
mp, err := fsutils.Dir()
if err != nil {
return "", err
}
Expand Down
145 changes: 145 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package app

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"

"github.com/davrodpin/mole/fsutils"
"github.com/gofrs/uuid"
"github.com/hpcloud/tail"
)

const (
InstancePidFile = "pid"
InstanceLogFile = "mole.log"
)

// DetachedInstance holds the location to directories and files associated
// with an application instance running on background.
type DetachedInstance struct {
// Id is the unique identifier of a detached application instance. The value
// can be either the alias or a unique alphanumeric value.
Id string
// LogFile points to a file path in the file system where the application
// log file is stored.
LogFile string
// PidFile points to a file path in the file system where the application
// procces identifier is stored.
PidFile string
}

// NewDetachedInstance returns a new instance of DetachedInstance, making sure
// the application instance directory is created.
func NewDetachedInstance(id string) (*DetachedInstance, error) {
instanceDir, err := fsutils.Dir()
if err != nil {
return nil, err
}

if id == "" {
u, err := uuid.NewV4()
if err != nil {
return nil, fmt.Errorf("could not auto generate app instance id: %v", err)
}
id = u.String()[:8]
}

home := filepath.Join(instanceDir, id)

if _, err := os.Stat(home); os.IsNotExist(err) {
err := os.MkdirAll(home, 0755)
if err != nil {
return nil, err
}
}

pfl, err := GetPidFileLocation(id)
if err != nil {
return nil, err
}

if _, err = os.Stat(pfl); !os.IsNotExist(err) {
_, err = os.Stat(pfl)
data, err := ioutil.ReadFile(pfl)
if err != nil {
return nil, fmt.Errorf("something went wrong while reading from pid file %s: %v", pfl, err)
}

pid := string(data)

if pid != "" {
return nil, fmt.Errorf("an instance of mole with pid %s seems to be already running", pid)
}

}

pf, err := os.Create(pfl)
if err != nil {
return nil, fmt.Errorf("could not create pid file for application instance %s: %v", id, err)
}
defer pf.Close()
pf.WriteString(strconv.Itoa(os.Getpid()))

lfl, err := GetLogFileLocation(id)
if err != nil {
return nil, err
}

lf, err := os.Create(lfl)
if err != nil {
return nil, fmt.Errorf("could not create log file for application instance %s: %v", id, err)
}
defer lf.Close()

return &DetachedInstance{
Id: id,
LogFile: lfl,
PidFile: pfl,
}, nil
}

// GetPidFileLocation return the file system location of the application
// instance in the file system.
func GetPidFileLocation(id string) (string, error) {
d, err := fsutils.Dir()
if err != nil {
return "", err
}

pfp := filepath.Join(d, id, InstancePidFile)

return pfp, nil
}

// GetLogFileLocation return the file system location of the file where all
// log messages are saved for an specific detached application instance.
func GetLogFileLocation(id string) (string, error) {
d, err := fsutils.Dir()
if err != nil {
return "", err
}

lfp := filepath.Join(d, id, InstanceLogFile)

return lfp, nil
}

func ShowLogs(id string, follow bool) error {
lfl, err := GetLogFileLocation(id)
if err != nil {
return err
}

t, err := tail.TailFile(lfl, tail.Config{Follow: follow})
if err != nil {
return err
}
for line := range t.Lines {
fmt.Println(line.Text)
}

return nil
}
104 changes: 104 additions & 0 deletions app/app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package app_test

import (
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/davrodpin/mole/app"
)

var (
// home is a temporary directory that acts as the user home directory.
// It is used on most tests to validates files created by Mole and their
// contents.
home string
)

func TestDetachedInstanceFileLocations(t *testing.T) {
id := "TestDetachedInstanceFileLocations"

di, err := app.NewDetachedInstance(id)
if err != nil {
t.Errorf("error creating a new detached instance: %v", err)
}

if _, err := os.Stat(di.LogFile); os.IsNotExist(err) {
t.Errorf("log file does not exist: %v", err)
}

if _, err := os.Stat(di.PidFile); os.IsNotExist(err) {
t.Errorf("pid file does not exist: %v", err)
}

lfl, err := app.GetLogFileLocation(id)
if err != nil {
t.Errorf("error retrieving log file location: %v", err)
}

if _, err := os.Stat(lfl); os.IsNotExist(err) {
t.Errorf("log file does not exist: %v", err)
}

}

func TestDetachedInstanceGeneratedId(t *testing.T) {

di, err := app.NewDetachedInstance("")
if err != nil {
t.Errorf("error creating a new detached instance: %v", err)
}

if di.Id == "" {
t.Errorf("detached instance id is empty")
}
}

func TestDetachedInstanceAlreadyRunning(t *testing.T) {
id := "TestDetachedInstanceAlreadyRunning"

os.MkdirAll(filepath.Join(home, ".mole", id), 0755)
pidFileLocation := filepath.Join(home, ".mole", id, app.InstancePidFile)
ioutil.WriteFile(pidFileLocation, []byte("1234"), 0644)

_, err := app.NewDetachedInstance(id)

if err == nil {
t.Errorf("error expected but got nil")
}

}

func TestShowLogs(t *testing.T) {
id := "TestDetachedInstanceAlreadyRunning"

os.MkdirAll(filepath.Join(home, ".mole", id), 0755)
logFileLocation := filepath.Join(home, ".mole", id, app.InstanceLogFile)
ioutil.WriteFile(logFileLocation, []byte("first log message\nsecond log message\nthird log message\n"), 0644)

err := app.ShowLogs(id, false)

if err != nil {
t.Errorf("error showing logs: %v", err)
}

}

func TestMain(m *testing.M) {
var err error

home, err = ioutil.TempDir("", "mole")
if err != nil {
os.Exit(1)
}

os.Setenv("HOME", home)
os.Setenv("USERPROFILE", home)

code := m.Run()

os.RemoveAll(home)

os.Exit(code)
}
2 changes: 2 additions & 0 deletions app/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package app contains abstractions to manage an application instance of mole .
package app
Loading