mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 20:11:54 +00:00
This change introduces an `mi2`-like experience for interacting with MSP databases. By default we use the new readonly-SA introduced in https://github.com/sourcegraph/sourcegraph/pull/59105, otherwise with the `--write-access` flag you can connect as the same user as the Cloud Run workload, which gives a lot more permissions. An alias, `sg msp pg connect`, is available for those less inclined to type out the entire `postgresql` subcommand name. Closes https://github.com/sourcegraph/managed-services/issues/207 ## Test plan Applied to `msp-testbed`, which has a PG instance and provisioned tables. Try both service accounts: ``` sg msp pg connect --write-access msp-testbed test sg msp pg connect msp-testbed test ```  With both of the above: ``` primary=> select * from users; id | created_at | updated_at | deleted_at | external_id | name | avatar_url ----+------------+------------+------------+-------------+------+------------ (0 rows) ```
75 lines
2.1 KiB
Go
75 lines
2.1 KiB
Go
// Initially copy-pasta from https://github.com/sourcegraph/controller/blob/main/internal/cloudsqlproxy/proxy.go
|
|
package cloudsqlproxy
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/sourcegraph/run"
|
|
|
|
"github.com/sourcegraph/sourcegraph/dev/sg/internal/std"
|
|
"github.com/sourcegraph/sourcegraph/lib/errors"
|
|
)
|
|
|
|
// CloudSQLProxy is a cloud-sql-proxy instance
|
|
//
|
|
// It uses the identity of the service account to connect to the database
|
|
// and the proxy can handle the authentication for the database and refresh
|
|
// the credentials as needed.
|
|
type CloudSQLProxy struct {
|
|
Token string
|
|
DBInstanceConnectionName string
|
|
ImpersonateServiceAccount string
|
|
Port int
|
|
}
|
|
|
|
func NewCloudSQLProxy(dbConnection string, iamUserEmail string, port int) (*CloudSQLProxy, error) {
|
|
return &CloudSQLProxy{
|
|
DBInstanceConnectionName: dbConnection,
|
|
ImpersonateServiceAccount: iamUserEmail,
|
|
Port: port,
|
|
}, nil
|
|
}
|
|
|
|
func (p *CloudSQLProxy) Start(ctx context.Context, timeoutSeconds int) error {
|
|
bin, err := Path()
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to get path to the cloud-sql-proxy binary")
|
|
}
|
|
|
|
proxyCmd := fmt.Sprintf("%s -i -p %d --impersonate-service-account=%s %s",
|
|
bin, p.Port, p.ImpersonateServiceAccount, p.DBInstanceConnectionName)
|
|
|
|
if timeoutSeconds > 0 {
|
|
var cancel context.CancelFunc
|
|
ctx, cancel = context.WithCancel(ctx)
|
|
defer cancel()
|
|
|
|
std.Out.WriteWarningf("The current session will terminate in %d seconds. Use '-session.timeout' to increase the session duration.",
|
|
timeoutSeconds)
|
|
time.AfterFunc(time.Duration(timeoutSeconds)*time.Second, func() {
|
|
select {
|
|
case <-ctx.Done():
|
|
return // nothing to do
|
|
default:
|
|
std.Out.WriteAlertf("The current session has timed out after %d seconds and will be terminated.",
|
|
timeoutSeconds)
|
|
cancel()
|
|
}
|
|
})
|
|
}
|
|
|
|
err = run.Cmd(ctx, proxyCmd).Run().StreamLines(func(line string) {
|
|
std.Out.Write(" [cloud-sql-proxy] " + line)
|
|
})
|
|
if err != nil {
|
|
if ctx.Err() == context.Canceled {
|
|
return nil
|
|
}
|
|
return errors.Wrap(err, "failed to start cloud-sql-proxy")
|
|
}
|
|
|
|
return nil
|
|
}
|