Skip to content
This repository has been archived by the owner on Nov 8, 2022. It is now read-only.

Commit

Permalink
Added unpackaging of plugin to load.
Browse files Browse the repository at this point in the history
  • Loading branch information
tiffanyfay committed Oct 16, 2015
1 parent 23080ae commit bb66172
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 3 deletions.
6 changes: 6 additions & 0 deletions control/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/intelsdi-x/pulse/core/ctypes"
"github.com/intelsdi-x/pulse/core/perror"
"github.com/intelsdi-x/pulse/pkg/psigning"
"github.com/intelsdi-x/pulse/pkg/unpackage"
)

// Plugin token = token generated by plugin and passed to control
Expand Down Expand Up @@ -253,6 +254,11 @@ func (p *pluginControl) Load(path string) (core.CatalogedPlugin, perror.PulseErr
}
}

path, _, e := unpackage.Unpackager(path)
if e != nil {
return nil, perror.New(e)
}

controlLogger.WithFields(f).Info("plugin load called")
if !p.Started {
pe := perror.New(ErrControllerNotStarted)
Expand Down
32 changes: 32 additions & 0 deletions control/control_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ func (l *listenToPluginEvent) HandleGomitEvent(e gomit.Event) {
}
}

var (
AciPath = path.Join(strings.TrimRight(PulsePath, "build"), "pkg/unpackage/")
AciFile = "pulse-collector-plugin-dummy1.darwin-x86_64.aci"
)

type mocksigningManager struct {
signed bool
}
Expand Down Expand Up @@ -253,6 +258,7 @@ func TestLoad(t *testing.T) {
// So(len(c.pluginManager.LoadedPlugins.Table()), ShouldBeGreaterThan, 0)
})

//Plugin Signing
Convey("loads successfully with trust enabled", func() {
c := New()
c.pluginTrust = 1
Expand Down Expand Up @@ -288,6 +294,32 @@ func TestLoad(t *testing.T) {
time.Sleep(100)
So(err, ShouldNotBeNil)
})

//Unpackaging
Convey("load untar error with package", func() {
c := New()
lpe := newListenToPluginEvent()
c.eventManager.RegisterHandler("Control.PluginLoaded", lpe)
c.Start()
PackagePath := path.Join(AciPath, "dummy.aci")
_, err := c.Load(PackagePath)
time.Sleep(100)
So(err, ShouldNotBeNil)
So(c.pluginManager.all(), ShouldBeEmpty)
})

Convey("No exec file error", func() {
c := New()
lpe := newListenToPluginEvent()
c.eventManager.RegisterHandler("Control.PluginLoaded", lpe)
c.Start()
PackagePath := path.Join(AciPath, "noExec.aci")
_, err := c.Load(PackagePath)
time.Sleep(100)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldContainSubstring, "Error no executable files found")
So(c.pluginManager.all(), ShouldBeEmpty)
})
})
} else {
fmt.Printf("PULSE_PATH not set. Cannot test %s plugin.\n", PluginName)
Expand Down
2 changes: 1 addition & 1 deletion pkg/psigning/psigning.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var (
ErrKeyringFileNotFound = errors.New("Keyring file (.gpg) not found")
ErrUnableToReadKeyring = errors.New("Unable to read keyring")
ErrSignedFileNotFound = errors.New("Signed file not found")
ErrSignatureFileNotFound = errors.New("Signature file (.asc) not found")
ErrSignatureFileNotFound = errors.New("Signature file (.asc) not found. Did you use the -a flag?")
ErrCheckSignature = errors.New("Error checking signature")
)

Expand Down
2 changes: 1 addition & 1 deletion pkg/psigning/psigning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ func TestValidateSignature(t *testing.T) {

Convey("Invalid signature file", t, func() {
err := s.ValidateSignature(keyringFile, signedFile, "")
So(err.Error(), ShouldResemble, "Signature file (.asc) not found")
So(err.Error(), ShouldResemble, "Signature file (.asc) not found. Did you use the -a flag?")
})
}
Binary file added pkg/unpackage/noExec.aci
Binary file not shown.
Binary file not shown.
Binary file not shown.
236 changes: 236 additions & 0 deletions pkg/unpackage/unpackage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*
http://www.apache.org/licenses/LICENSE-2.0.txt
Copyright 2015 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package unpackage

import (
"archive/tar"
"bufio"
"compress/gzip"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"

log "github.com/Sirupsen/logrus"
)

var (
ErrOpen = errors.New("Error opening file")
ErrRead = errors.New("Error reading file")
ErrSeek = errors.New("Error seeking file")
ErrCreatingFile = errors.New("Error creating file")
ErrCopyingFile = errors.New("Error copying file")
ErrUnzip = errors.New("Error unzipping file")
ErrReadManifest = errors.New("Error reading manifest")
ErrMkdirAll = errors.New("Error making directory")
ErrChmod = errors.New("Error changing file permissions")
ErrFileRead = errors.New("Error reading file")
ErrNoExecFiles = errors.New("Error no executable files found")
ErrNext = errors.New("Error iterating through tar file")
ErrGetContentType = errors.New("Error getting content type")
ErrUnmarshalJSON = errors.New("Error unmarshaling JSON")
ErrUntar = errors.New("Error untarring file")
)

var upkgLogger *log.Entry = log.WithFields(log.Fields{
"_module": "unpackage",
})

//If package is an ACI, Untar package and Unmarshal ACI manifest
func Unpackager(path string) (string, *Manifest, error) {
upkgLogger = upkgLogger.WithField("_block", "Unpackager")

//Check if file has the extension .aci
if !strings.Contains(path, ".aci") {
return path, nil, nil
}

f, err := os.Open(path)
if err != nil {
return "", nil, fmt.Errorf("%v: %v\n%v", ErrOpen, path, err)
}
defer f.Close()

//Untar loaded package
data, err := Uncompress(path, f)
if err != nil {
return "", nil, err
}
//Read JSON manifest
manifest, err := UnmarshalJSON(data)
if err != nil {
return "", nil, err
}

dir := strings.Replace(path, ".aci", "", -1) + "/rootfs"

//Get executable file name and update path
if len(manifest.App.Exec) < 1 {
return "", nil, ErrNoExecFiles
}
exec := manifest.App.Exec[0]
path = dir + exec

return path, manifest, nil
}

func Uncompress(path string, f *os.File) ([]byte, error) {
upkgLogger = upkgLogger.WithField("_block", "Uncompress")
upkgLogger.Info("Uncompressing Files")

fileType, err := GetContentType(path, f)
if err != nil {
return nil, err
}
if fileType == "application/x-gzip" {
reader, err := Unzip(path, f)
if err != nil {
return nil, err
}
return Untar(path, reader)
}
return Untar(path, bufio.NewReader(f))
}

//Untar files and get manifest
func Untar(path string, reader *bufio.Reader) ([]byte, error) {
upkgLogger = upkgLogger.WithField("_block", "Untar")
upkgLogger.Info("Untarring Files")

fileMode := os.FileMode(0755)
mdata := []byte{} //manifest data
tr := tar.NewReader(reader)
dir := filepath.Join(strings.Replace(path, ".aci", "", -1), "/")
err := os.MkdirAll(dir, fileMode)
if err != nil {
return nil, fmt.Errorf("%v: %v\n%v", ErrMkdirAll, dir, err)
}
upkgLogger.Info("Creating directory and writing files to: ", dir)

for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, fmt.Errorf("%v\n%v", ErrNext, err)
}
file := filepath.Join(dir, hdr.Name)

//Check if header type is a file or directory
switch hdr.Typeflag {
case tar.TypeReg:
//Create files
fmt.Println("x", hdr.Name)
w, err := os.Create(file)
if err != nil {
return nil, fmt.Errorf("%v: %v\n%v", ErrCreatingFile, file, err)
}
_, err = io.Copy(w, tr)
if err != nil {
return nil, fmt.Errorf("%v: %v\n%v", ErrCopyingFile, file, err)
}
err = os.Chmod(file, fileMode)
if err != nil {
return nil, fmt.Errorf("%v: %v\n%v", ErrChmod, file, err)
}
//Get manifest data for unmarshaling
if hdr.Name == "manifest" {
mdata, err = ioutil.ReadFile(file)
if err != nil {
return nil, fmt.Errorf("%v: %v\n%v", ErrReadManifest, file, err)
}
}
w.Close()
case tar.TypeDir:
//Create directory
fmt.Println("x", hdr.Name)
err = os.MkdirAll(file, fileMode)
if err != nil {
return nil, fmt.Errorf("%v: %v\n%v", ErrMkdirAll, file, err)
}
default:
return nil, fmt.Errorf("%v: %v", ErrUntar, hdr.Name)
}
}
return mdata, nil
}

//Get the content type of the file
func GetContentType(path string, file *os.File) (string, error) {
upkgLogger = upkgLogger.WithField("_block", "GetContentType")

b := make([]byte, 512)
_, err := file.Read(b)
if err != nil {
return "", fmt.Errorf("%v: %v\n%v", ErrRead, path, err)
}
fileType := http.DetectContentType(b)
_, err = file.Seek(0, 0)
if err != nil {
return "", fmt.Errorf("%v: %v\n%v", ErrSeek, path, err)
}
return fileType, nil
}

func Unzip(path string, f *os.File) (*bufio.Reader, error) {
upkgLogger = upkgLogger.WithField("_block", "Unzip")
reader, err := gzip.NewReader(bufio.NewReader(f))
if err != nil {
return nil, fmt.Errorf("%v: %v\n%v", ErrUnzip, path, err)
}
return bufio.NewReader(reader), nil
}

type Labels struct {
Name string `json:"name"`
Value string `json:"value"`
}

type App struct {
Exec []string `json:"exec"`
Group int64 `json:"group,string"`
User int64 `json:"user,string"`
}

type Manifest struct {
AcKind string `json:"acKind"`
AcVersion string `json:"acVersion"`
Name string `json:"name"`
Labels []Labels `json:"labels"`
App App `json:"app"`
}

//Unmarshal ACI manifest
func UnmarshalJSON(data []byte) (*Manifest, error) {
upkgLogger = upkgLogger.WithField("_block", "UnmarshalJSON")
upkgLogger.Info("Unmarshaling JSON")

manifest := &Manifest{}
err := json.Unmarshal(data, manifest)
if err != nil {
return nil, fmt.Errorf("%v\n%v", ErrUnmarshalJSON, err)
}
return manifest, nil
}
Loading

0 comments on commit bb66172

Please sign in to comment.