Compare commits

...

5 Commits
0.2.4 ... 0.2.8

Author SHA1 Message Date
38f26b213f Clear snapshot when container doesn't exist
This clears up a scenario where a container can be deleted but
its snapshot is not.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2019-12-28 20:01:01 +00:00
6c3fe813fd Extract PrepareImage
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2019-12-28 19:09:42 +00:00
13d28bd2db Extract Service struct
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2019-12-28 18:32:13 +00:00
f3f6225674 Bump faasd version
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2019-12-28 16:46:53 +00:00
e4ed9e5b91 Fix typo
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2019-12-28 16:46:08 +00:00
4 changed files with 127 additions and 111 deletions

View File

@ -86,17 +86,17 @@ go build
```sh ```sh
# For x86_64 # For x86_64
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.2/faasd" \ sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.5/faasd" \
-o "/usr/local/bin/faasd" \ -o "/usr/local/bin/faasd" \
&& sudo chmod a+x "/usr/local/bin/faasd" && sudo chmod a+x "/usr/local/bin/faasd"
# armhf # armhf
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.2/faasd-armhf" \ sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.5/faasd-armhf" \
-o "/usr/local/bin/faasd" \ -o "/usr/local/bin/faasd" \
&& sudo chmod a+x "/usr/local/bin/faasd" && sudo chmod a+x "/usr/local/bin/faasd"
# arm64 # arm64
sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.2/faasd-arm64" \ sudo curl -fSLs "https://github.com/alexellis/faasd/releases/download/0.2.5/faasd-arm64" \
-o "/usr/local/bin/faasd" \ -o "/usr/local/bin/faasd" \
&& sudo chmod a+x "/usr/local/bin/faasd" && sudo chmod a+x "/usr/local/bin/faasd"
``` ```

View File

@ -23,7 +23,7 @@ func runInstall(_ *cobra.Command, _ []string) error {
return err return err
} }
err := binExists("/usr/local/bin/", "faasd") err = binExists("/usr/local/bin/", "faasd")
if err != nil { if err != nil {
return err return err
} }

117
pkg/service/service.go Normal file
View File

@ -0,0 +1,117 @@
package service
import (
"context"
"fmt"
"log"
"sync"
"time"
"github.com/containerd/containerd"
"github.com/containerd/containerd/errdefs"
"golang.org/x/sys/unix"
)
// Remove removes a container
func Remove(ctx context.Context, client *containerd.Client, name string) error {
container, containerErr := client.LoadContainer(ctx, name)
if containerErr == nil {
found := true
t, err := container.Task(ctx, nil)
if err != nil {
if errdefs.IsNotFound(err) {
found = false
} else {
return fmt.Errorf("unable to get task %s: ", err)
}
}
if found {
status, _ := t.Status(ctx)
fmt.Printf("Status of %s is: %s\n", name, status.Status)
log.Printf("Need to kill %s\n", name)
err := killTask(ctx, t)
if err != nil {
return fmt.Errorf("error killing task %s, %s, %s", container.ID(), name, err)
}
}
err = container.Delete(ctx, containerd.WithSnapshotCleanup)
if err != nil {
return fmt.Errorf("error deleting container %s, %s, %s", container.ID(), name, err)
}
} else {
service := client.SnapshotService("")
key := name + "snapshot"
if _, err := client.SnapshotService("").Stat(ctx, key); err == nil {
service.Remove(ctx, key)
}
}
return nil
}
// From Stellar
func killTask(ctx context.Context, task containerd.Task) error {
wg := &sync.WaitGroup{}
wg.Add(1)
var err error
go func() {
defer wg.Done()
if task != nil {
wait, err := task.Wait(ctx)
if err != nil {
err = fmt.Errorf("error waiting on task: %s", err)
return
}
if err := task.Kill(ctx, unix.SIGTERM, containerd.WithKillAll); err != nil {
log.Printf("error killing container task: %s", err)
}
select {
case <-wait:
task.Delete(ctx)
return
case <-time.After(5 * time.Second):
if err := task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll); err != nil {
log.Printf("error force killing container task: %s", err)
}
return
}
}
}()
wg.Wait()
return err
}
func PrepareImage(ctx context.Context, client *containerd.Client, imageName, snapshotter string) (containerd.Image, error) {
var empty containerd.Image
image, err := client.GetImage(ctx, imageName)
if err != nil {
if !errdefs.IsNotFound(err) {
return empty, err
}
img, err := client.Pull(ctx, imageName, containerd.WithPullUnpack)
if err != nil {
return empty, fmt.Errorf("cannot pull: %s", err)
}
image = img
}
unpacked, err := image.IsUnpacked(ctx, snapshotter)
if err != nil {
return empty, fmt.Errorf("cannot check if unpacked: %s", err)
}
if !unpacked {
if err := image.Unpack(ctx, snapshotter); err != nil {
return empty, fmt.Errorf("cannot unpack: %s", err)
}
}
return image, nil
}

View File

@ -8,15 +8,12 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"sync"
"time"
"github.com/alexellis/faasd/pkg/service"
"github.com/alexellis/faasd/pkg/weave" "github.com/alexellis/faasd/pkg/weave"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cio" "github.com/containerd/containerd/cio"
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs"
"golang.org/x/sys/unix"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci" "github.com/containerd/containerd/oci"
@ -48,7 +45,7 @@ func (s *Supervisor) Remove(svcs []Service) error {
ctx := namespaces.WithNamespace(context.Background(), "default") ctx := namespaces.WithNamespace(context.Background(), "default")
for _, svc := range svcs { for _, svc := range svcs {
err := removeContainer(ctx, s.client, svc.Name) err := service.Remove(ctx, s.client, svc.Name)
if err != nil { if err != nil {
return err return err
} }
@ -75,7 +72,7 @@ func (s *Supervisor) Start(svcs []Service) error {
for _, svc := range svcs { for _, svc := range svcs {
fmt.Printf("Preparing: %s with image: %s\n", svc.Name, svc.Image) fmt.Printf("Preparing: %s with image: %s\n", svc.Name, svc.Image)
img, err := prepareImage(ctx, s.client, svc.Image) img, err := service.PrepareImage(ctx, s.client, svc.Image, defaultSnapshotter)
if err != nil { if err != nil {
return err return err
} }
@ -87,13 +84,13 @@ func (s *Supervisor) Start(svcs []Service) error {
for _, svc := range svcs { for _, svc := range svcs {
fmt.Printf("Reconciling: %s\n", svc.Name) fmt.Printf("Reconciling: %s\n", svc.Name)
image := images[svc.Name] containerErr := service.Remove(ctx, s.client, svc.Name)
containerErr := removeContainer(ctx, s.client, svc.Name)
if containerErr != nil { if containerErr != nil {
return containerErr return containerErr
} }
image := images[svc.Name]
mounts := []specs.Mount{} mounts := []specs.Mount{}
if len(svc.Mounts) > 0 { if len(svc.Mounts) > 0 {
for _, mnt := range svc.Mounts { for _, mnt := range svc.Mounts {
@ -199,37 +196,6 @@ func (s *Supervisor) Start(svcs []Service) error {
return nil return nil
} }
func prepareImage(ctx context.Context, client *containerd.Client, imageName string) (containerd.Image, error) {
snapshotter := defaultSnapshotter
var empty containerd.Image
image, err := client.GetImage(ctx, imageName)
if err != nil {
if !errdefs.IsNotFound(err) {
return empty, err
}
img, err := client.Pull(ctx, imageName, containerd.WithPullUnpack)
if err != nil {
return empty, fmt.Errorf("cannot pull: %s", err)
}
image = img
}
unpacked, err := image.IsUnpacked(ctx, snapshotter)
if err != nil {
return empty, fmt.Errorf("cannot check if unpacked: %s", err)
}
if !unpacked {
if err := image.Unpack(ctx, snapshotter); err != nil {
return empty, fmt.Errorf("cannot unpack: %s", err)
}
}
return image, nil
}
func getIP(containerID string, taskPID uint32) string { func getIP(containerID string, taskPID uint32) string {
// https://github.com/weaveworks/weave/blob/master/net/netdev.go // https://github.com/weaveworks/weave/blob/master/net/netdev.go
@ -274,70 +240,3 @@ func withOCIArgs(args []string) oci.SpecOpts {
} }
} }
// From Stellar
func killTask(ctx context.Context, task containerd.Task) error {
wg := &sync.WaitGroup{}
wg.Add(1)
var err error
go func() {
defer wg.Done()
if task != nil {
wait, err := task.Wait(ctx)
if err != nil {
err = fmt.Errorf("error waiting on task: %s", err)
return
}
if err := task.Kill(ctx, unix.SIGTERM, containerd.WithKillAll); err != nil {
log.Printf("error killing container task: %s", err)
}
select {
case <-wait:
task.Delete(ctx)
return
case <-time.After(5 * time.Second):
if err := task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll); err != nil {
log.Printf("error force killing container task: %s", err)
}
return
}
}
}()
wg.Wait()
return err
}
func removeContainer(ctx context.Context, client *containerd.Client, name string) error {
container, containerErr := client.LoadContainer(ctx, name)
if containerErr == nil {
found := true
t, err := container.Task(ctx, nil)
if err != nil {
if errdefs.IsNotFound(err) {
found = false
} else {
return fmt.Errorf("unable to get task %s: ", err)
}
}
if found {
status, _ := t.Status(ctx)
fmt.Printf("Status of %s is: %s\n", name, status.Status)
log.Printf("Need to kill %s\n", name)
err := killTask(ctx, t)
if err != nil {
return fmt.Errorf("error killing task %s, %s, %s", container.ID(), name, err)
}
}
err = container.Delete(ctx, containerd.WithSnapshotCleanup)
if err != nil {
return fmt.Errorf("error deleting container %s, %s, %s", container.ID(), name, err)
}
}
return nil
}