pkg/bundle/container.go (85 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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 bundle
import (
"bytes"
"compress/gzip"
"fmt"
"io"
bundlev1 "github.com/elastic/harp/api/gen/go/harp/bundle/v1"
containerv1 "github.com/elastic/harp/api/gen/go/harp/container/v1"
"github.com/elastic/harp/pkg/container"
"github.com/elastic/harp/pkg/sdk/types"
)
// Statistic hold bundle statistic information
type Statistic struct {
PackageCount uint32
CSOCompliantPackageNameCount uint32
SecretCount uint32
}
const (
bundleContentType = "application/vnd.harp.v1.Bundle"
gzipCompressionLevel = 9
)
// FromContainerReader returns a Bundle extracted from a secret container.
func FromContainerReader(r io.Reader) (*bundlev1.Bundle, error) {
// Check parameters
if types.IsNil(r) {
return nil, fmt.Errorf("unable to process nil reader")
}
// Load secret container
c, err := container.Load(r)
if err != nil {
return nil, fmt.Errorf("unable to load Bundle: %w", err)
}
// Delegate to bundle loader
return FromContainer(c)
}
// ToContainerWriter returns a Bundle packaged as a secret container.
func ToContainerWriter(w io.Writer, b *bundlev1.Bundle) error {
// Check parameters
if types.IsNil(w) {
return fmt.Errorf("unable to process nil writer")
}
if b == nil {
return fmt.Errorf("unable to process nil bundle")
}
// Create a container
c, err := ToContainer(b)
if err != nil {
return fmt.Errorf("unable to wrap bundle as a container: %w", err)
}
// Prepare secret container
return container.Dump(w, c)
}
// FromContainer unwraps a Bundle from a secret container.
func FromContainer(c *containerv1.Container) (*bundlev1.Bundle, error) {
// Check parameters
if types.IsNil(c) {
return nil, fmt.Errorf("unable to process nil container")
}
// Check headers
if types.IsNil(c.Headers) {
return nil, fmt.Errorf("unable to process nil container headers")
}
if c.Headers.ContentType != bundleContentType {
return nil, fmt.Errorf("invalid content type for Bundle loader")
}
if c.Headers.ContentEncoding != "gzip" {
return nil, fmt.Errorf("invalid content encoding for Bundle loader")
}
// Decompress bundle
zr, err := gzip.NewReader(bytes.NewReader(c.Raw))
if err != nil {
return nil, fmt.Errorf("unable to initialize compression reader")
}
// Delegate to bundle loader
return Load(zr)
}
// ToContainer wrpas a Bundle as a container object.
func ToContainer(b *bundlev1.Bundle) (*containerv1.Container, error) {
if b == nil {
return nil, fmt.Errorf("unable to process nil bundle")
}
// Dump bundle
payload := &bytes.Buffer{}
// Compress with gzip
zw, errGz := gzip.NewWriterLevel(payload, gzipCompressionLevel)
if errGz != nil {
return nil, fmt.Errorf("unable to compress bundle content: %w", errGz)
}
// Delegate to Bundle Writer
if errDump := Dump(zw, b); errDump != nil {
return nil, fmt.Errorf("unable to dump container: %w", errDump)
}
// Close gzip writer
if errGz = zw.Close(); errGz != nil {
return nil, fmt.Errorf("unable to close compression writer: %w", errGz)
}
// Return container
return &containerv1.Container{
Headers: &containerv1.Header{
ContentEncoding: "gzip",
ContentType: bundleContentType,
},
Raw: payload.Bytes(),
}, nil
}