blob: 3cee0225c6222cc8883d4db383a1ca8893defe7d [file] [log] [blame]
// Package common has functions useful across its peer modules.
package common
import (
"context"
"strings"
"time"
"cloud.google.com/go/pubsub"
"go.skia.org/infra/go/executil"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/machine/go/machineserver/config"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
)
const commandTimeout = 5 * time.Second
// NewPubSubClient creates a new pubsub client from the given config and also
// creates the associated topic specified in the instance config.
func NewPubSubClient(ctx context.Context, local bool, instanceConfig config.InstanceConfig) (*pubsub.Client, *pubsub.Topic, error) {
ts, err := google.DefaultTokenSource(ctx, pubsub.ScopePubSub)
if err != nil {
return nil, nil, skerr.Wrapf(err, "Failed to create token source.")
}
pubsubClient, err := pubsub.NewClient(ctx, instanceConfig.Source.Project, option.WithTokenSource(ts))
if err != nil {
return nil, nil, skerr.Wrapf(err, "Failed to create PubSub client for project %s", instanceConfig.Source.Project)
}
topic := pubsubClient.Topic(instanceConfig.Source.Topic)
exists, err := topic.Exists(ctx)
if err != nil {
return nil, nil, skerr.Wrapf(err, "Failed to check existence of PubSub topic %q", topic.ID())
}
if !exists {
if _, err := pubsubClient.CreateTopic(ctx, topic.ID()); err != nil {
return nil, nil, skerr.Wrapf(err, "Failed to create PubSub topic %q", topic.ID())
}
}
return pubsubClient, topic, nil
}
// TrimmedCommandOutput runs a command and returns its combined stdout and stdrerr
// (whitespace-trimmed), timing out after a period prescribed by commandTimeout. If the command
// returns a non-zero exit code, returned error is an exec.ExitError.
//
// idevice commands tend to return everything--both errors and normal output--on stderr. However,
// they don't advertise that as part of their contract, so we take both stdout and stderr for
// durability.
func TrimmedCommandOutput(ctx context.Context, commandName string, args ...string) (string, error) {
ctx, cancel := context.WithTimeout(ctx, commandTimeout)
defer cancel()
cmd := executil.CommandContext(ctx, commandName, args...)
output_bytes, err := cmd.CombinedOutput()
return strings.TrimSpace(string(output_bytes)), err // lop off newline
}