Skip to content

Commit

Permalink
added pid files. permission denied error
Browse files Browse the repository at this point in the history
  • Loading branch information
ivcosla committed Jun 10, 2019
1 parent bcae8da commit 6ca95ae
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 3 deletions.
69 changes: 68 additions & 1 deletion pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
package node

import (
"bufio"
"context"
"errors"
"fmt"
"github.com/skycoin/skywire/pkg/util/pathutil"
"io"
"net"
"net/rpc"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"time"
Expand Down Expand Up @@ -151,6 +155,7 @@ func NewNode(config *Config) (*Node, error) {
RoutingTable: node.rt,
RouteFinder: routeFinder.NewHTTP(config.Routing.RouteFinder, time.Duration(config.Routing.RouteFinderTimeout)),
SetupNodes: config.Routing.SetupNodes,

}
r := router.New(rConfig)
node.router = r
Expand Down Expand Up @@ -203,6 +208,8 @@ func (node *Node) Start() error {
}
node.logger.Info("Connected to messaging servers")

pathutil.EnsureDir(node.dir())
node.closePreviousApps()
for _, ac := range node.appsConf {
if !ac.AutoStart {
continue
Expand Down Expand Up @@ -239,6 +246,58 @@ func (node *Node) Start() error {
return nil
}

func (node *Node) dir() string {
return pathutil.NodeDir(node.config.Node.StaticPubKey)
}

func (node *Node) pidFile() *os.File {
f, err := os.OpenFile(filepath.Join(node.dir(),"apps.pid"), os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}

return f
}

func (node *Node) closePreviousApps() {
pids := node.pidFile()
defer pids.Close() // nocheck: err

scanner := bufio.NewScanner(pids)
for scanner.Scan() {
appInfo := strings.Split(scanner.Text(), " ")
if len(appInfo) != 2 {
node.logger.Fatal("error parsing %s. Err: %s", pids.Name(), errors.New("line should be: [app name] [pid]"))
}

pid, err := strconv.Atoi(appInfo[1])
if err != nil {
node.logger.Fatal("error parsing %s. Err: %s", pids.Name(), err)
}

node.stopUnhandledApp(appInfo[0], pid)
}

// empty file
pathutil.AtomicWriteFile(pids.Name(), []byte{})
}

func (node *Node) stopUnhandledApp(name string, pid int) {
p, err := os.FindProcess(pid)
if err != nil {
node.logger.Infof("Previous app %s ran by this node with pid: %d not found", name, pid)
return
}

err = p.Signal(syscall.SIGKILL)
if err != nil {
node.logger.Warnf("Found hanged app %s with pid %d previously ran by this node, but unable to kill it: %s", name, pid, err)
return
}

node.logger.Infof("Found and killed hanged app %s with pid %d previously ran by this node", name, pid)
}

// Close safely stops spawned Apps and messaging Node.
func (node *Node) Close() (err error) {
if node.rpcListener != nil {
Expand Down Expand Up @@ -357,6 +416,8 @@ func (node *Node) SpawnApp(config *AppConfig, startCh chan<- struct{}) error {
bind.pid = pid
node.startedMu.Unlock()
appCh <- node.executer.Wait(cmd)

node.persistPID(config.App, pid)
}()

srvCh := make(chan error)
Expand Down Expand Up @@ -389,6 +450,11 @@ func (node *Node) SpawnApp(config *AppConfig, startCh chan<- struct{}) error {
return appErr
}

func (node *Node) persistPID(name string, pid int) {
pidF := node.pidFile()
pathutil.AtomicAppendToFile(pidF.Name(), []byte(fmt.Sprintf("%s %d\n", name, pid)))
}

// StopApp stops running App.
func (node *Node) StopApp(appName string) error {
node.startedMu.Lock()
Expand Down Expand Up @@ -445,6 +511,7 @@ func (exc *osExecuter) Start(cmd *exec.Cmd) (int, error) {
exc.mu.Lock()
exc.processes = append(exc.processes, cmd.Process)
exc.mu.Unlock()

return cmd.Process.Pid, nil
}

Expand All @@ -457,7 +524,7 @@ func (exc *osExecuter) Stop(pid int) (err error) {
continue
}

if sigErr := process.Signal(syscall.SIGTERM); sigErr != nil && err == nil {
if sigErr := process.Signal(syscall.SIGKILL); sigErr != nil && err == nil {
err = sigErr
}
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/router/app_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package router
import (
"encoding/json"
"errors"

"github.com/skycoin/skycoin/src/util/logging"

"github.com/skycoin/skywire/pkg/app"
)

Expand Down Expand Up @@ -97,3 +95,4 @@ func (am *appManager) forwardAppPacket(payload []byte) error {

return am.callbacks.Forward(am.proto, packet)
}

62 changes: 62 additions & 0 deletions pkg/util/pathutil/homedir.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package pathutil

import (
"fmt"
"github.com/skycoin/skywire/pkg/cipher"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
)

Expand All @@ -17,3 +22,60 @@ func HomeDir() string {
}
return os.Getenv("HOME")
}

// NodeDir returns a path to a directory used to store specific node configuration. Such dir is ~/.skywire/{PK}
func NodeDir(pk cipher.PubKey) string {
return filepath.Join(HomeDir(),".skycoin","skywire",pk.String())
}

// EnsureDir attempts to create given directory, panics if it fails to do so
func EnsureDir(path string) {
if _, err := os.Stat(path); os.IsNotExist(err) {
err := os.MkdirAll(path, 0644)
if err != nil {
panic(err)
}
}
}

// AtomicWriteFile creates a temp file in which to write data, then calls syscall.Rename to swap it and write it on
// filename for an atomic write. On failure temp file is removed and panics.
func AtomicWriteFile(filename string, data []byte) {
fmt.Println("got filename: ", filename)
dir, name := path.Split(filename)
f, err := ioutil.TempFile(dir, name)
if err != nil {
panic(err)
}

_, err = f.Write(data)
if err == nil {
err = f.Sync()
}
if closeErr := f.Close(); err == nil {
err = closeErr
}
if permErr := os.Chmod(f.Name(), 0644); err == nil {
err = permErr
}
if err == nil {
err = os.Rename(f.Name(), filename)
}

if err != nil {
os.Remove(f.Name())
}
panic(err)
}

// AtomicAppendToFile calls AtomicWriteFile but appends new data to destiny file
func AtomicAppendToFile(filename string, data []byte) {
fmt.Println("got filename: ", filename)
oldFile, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}

AtomicWriteFile(filename, append(oldFile, data...))
}

0 comments on commit 6ca95ae

Please sign in to comment.