mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
* Improve CLI documentation * feat: Allow workspace resources to attach multiple agents This enables a "kubernetes_pod" to attach multiple agents that could be for multiple services. Each agent is required to have a unique name, so SSH syntax is: `coder ssh <workspace>.<agent>` A resource can have zero agents too, they aren't required. * Add tree view * Improve table UI * feat: Allow workspace resources to attach multiple agents This enables a "kubernetes_pod" to attach multiple agents that could be for multiple services. Each agent is required to have a unique name, so SSH syntax is: `coder ssh <workspace>.<agent>` A resource can have zero agents too, they aren't required. * Rename `tunnel` to `skip-tunnel` This command was `true` by default, which causes a confusing user experience. * Add disclaimer about editing templates * Add help to template create * Improve workspace create flow * Add end-to-end test for config-ssh * Improve testing of config-ssh * Fix workspace list * Fix config ssh tests * Update cli/configssh.go Co-authored-by: Cian Johnston <public@cianjohnston.ie> * Fix requested changes * Remove socat requirement * Fix resources not reading in TTY Co-authored-by: Cian Johnston <public@cianjohnston.ie>
113 lines
2.3 KiB
Go
113 lines
2.3 KiB
Go
package provisionersdk
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
const (
|
|
// TemplateArchiveLimit represents the maximum size of a template in bytes.
|
|
TemplateArchiveLimit = 1 << 20
|
|
)
|
|
|
|
// Tar archives a directory.
|
|
func Tar(directory string, limit int64) ([]byte, error) {
|
|
var buffer bytes.Buffer
|
|
tarWriter := tar.NewWriter(&buffer)
|
|
totalSize := int64(0)
|
|
err := filepath.Walk(directory, func(file string, fileInfo os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
header, err := tar.FileInfoHeader(fileInfo, file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rel, err := filepath.Rel(directory, file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if strings.HasPrefix(rel, ".") {
|
|
// Don't archive hidden files!
|
|
return err
|
|
}
|
|
if strings.Contains(rel, ".tfstate") {
|
|
// Don't store tfstate!
|
|
return err
|
|
}
|
|
header.Name = rel
|
|
if err := tarWriter.WriteHeader(header); err != nil {
|
|
return err
|
|
}
|
|
if fileInfo.IsDir() {
|
|
return nil
|
|
}
|
|
data, err := os.Open(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer data.Close()
|
|
wrote, err := io.Copy(tarWriter, data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
totalSize += wrote
|
|
if limit != 0 && totalSize >= limit {
|
|
return xerrors.Errorf("Archive too big. Must be <= %d bytes", limit)
|
|
}
|
|
return data.Close()
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = tarWriter.Flush()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return buffer.Bytes(), nil
|
|
}
|
|
|
|
// Untar extracts the archive to a provided directory.
|
|
func Untar(directory string, archive []byte) error {
|
|
reader := tar.NewReader(bytes.NewReader(archive))
|
|
for {
|
|
header, err := reader.Next()
|
|
if xerrors.Is(err, io.EOF) {
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// #nosec
|
|
target := filepath.Join(directory, header.Name)
|
|
switch header.Typeflag {
|
|
case tar.TypeDir:
|
|
if _, err := os.Stat(target); err != nil {
|
|
if err := os.MkdirAll(target, 0755); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
case tar.TypeReg:
|
|
file, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Max file size of 10MB.
|
|
_, err = io.CopyN(file, reader, (1<<20)*10)
|
|
if xerrors.Is(err, io.EOF) {
|
|
err = nil
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = file.Close()
|
|
}
|
|
}
|
|
}
|