Skip to content

Instantly share code, notes, and snippets.

@derekperkins
Last active October 22, 2020 22:22
Show Gist options
  • Save derekperkins/cde013ec90b8f5cd3777c0ac3df91ffb to your computer and use it in GitHub Desktop.
Save derekperkins/cde013ec90b8f5cd3777c0ac3df91ffb to your computer and use it in GitHub Desktop.
Nozzle cloudidentity code
package internal
import (
"context"
"strconv"
"go.nozzle.io/namespaces/iam/iamapi"
iampb "go.nozzle.io/namespaces/iam/iamapi/iamapipb"
"go.nozzle.io/namespaces/workspaces/eventorapi/eventorpb"
"go.nozzle.io/namespaces/workspaces/workspacesapi"
"go.nozzle.io/namespaces/workspaces/workspacesapi/workspacespb"
"go.nozzle.io/pkg/cloudidentity"
"go.nozzle.io/pkg/e"
"go.nozzle.io/pkg/ngrpc"
"go.nozzle.io/pkg/workers"
)
// App holds the state and performs the business logic.
type App struct {
iamClient iamapi.IAMAPI
adminClient *cloudidentity.Client
workspaceClient workspacesapi.API
}
// Work performs the business logic.
func (a *App) Work(c context.Context, msg *workers.Message) {
// parse message
var event eventorpb.Event
err := ngrpc.JSONUnmarshal(msg.Data, &event)
if err != nil {
msg.Err = e.Wrap(err)
return
}
// filter out unwanted kinds until we get filtering in topics
if !(event.Kind == workspacespb.WorkspaceKind && event.Type == eventorpb.Event_TYPE_CREATE) {
return
}
// retrieve the workspace
ws, err := a.workspaceClient.GetWorkspaceByID(c, event.KindId)
if err != nil {
msg.Err = e.Wrap(err)
return
}
// Process event message
err = a.work(c, ws)
if err != nil {
msg.Err = err
}
}
func (a *App) work(c context.Context, ws *workspacespb.Workspace) error {
// create a google group for the workspace
groupID, err := a.adminClient.UpsertGroup(c, ws.Slug, strconv.FormatInt(ws.Id, 10), "A workspace group for managing BigQuery permissions")
if err != nil {
return e.Wrap(err, e.With("workspace_id", ws.Id))
}
// add all users in the workspace to the group
users, err := a.iamClient.ListUsers(c, &iampb.ListUsersRequest{
WorkspaceId: ws.Id,
})
if err != nil {
return e.Wrap(err)
}
// add users to the group
for _, user := range users {
err = a.adminClient.UpsertMember(c, groupID, user.Name, user.Email, cloudidentity.RoleMember)
if err != nil {
// report the error but try the other users
e.Wrap(err, e.With("user_id", user.Id)).Report(c)
}
}
return nil
}
// NewApp creates an instance of the application.
func NewApp(c context.Context, adminClient *cloudidentity.Client, iamClient iamapi.IAMAPI, workspaceClient workspacesapi.API) (*App, error) {
return &App{
adminClient: adminClient,
iamClient: iamClient,
workspaceClient: workspaceClient,
}, nil
}
package cloudidentity
import (
"context"
"net/http"
"google.golang.org/api/cloudidentity/v1"
"google.golang.org/api/googleapi"
)
// MemberRole is a members role.
type MemberRole string
var (
// RoleManager This role is only available if the
// Google Groups for Business is enabled using the Admin console.
// A MANAGER role can do everything done by an OWNER role except
// make a member an OWNER or delete the group. A group can have multiple MANAGER members.
RoleManager MemberRole = "MANAGER"
// RoleMember his role can subscribe to a group,
// view discussion archives, and view the group's membership list.
RoleMember MemberRole = "MEMBER"
// RoleOwner This role can send messages to the group,
// add or remove members, change member roles, change group's settings,
// and delete the group. An OWNER must be a member of the group.
// A group can have more than one OWNER.
RoleOwner MemberRole = "OWNER"
)
const groupParent = "customers/C03sdo746"
// NewClient will return a new instance of the admin client.
func NewClient(c context.Context) (*Client, error) {
client, err := cloudidentity.NewService(c)
if err != nil {
return nil, err
}
return &Client{
identityClient: client,
}, nil
}
// Client is used to manage google Admin settings.
type Client struct {
identityClient *cloudidentity.Service
}
// UpsertGroup create or update a group.
func (cl *Client) UpsertGroup(c context.Context, wsSlug, workspaceID, description string) (string, error) {
log.Debug(c, "upserting group "+wsSlug)
// check if exists before creating
resp, err := cl.identityClient.Groups.Lookup().GroupKeyId("workspaces-" + wsSlug + "@nozzle.app").Do()
if err != nil {
if gErr, ok := err.(*googleapi.Error); ok {
// group already exists ignore
if gErr.Code == http.StatusNotFound {
name, err := cl.createGroup(c, workspaceID, description)
if err != nil {
return "", err
}
return name, nil
}
}
return "", err
}
log.Debug(c, "upsert for group "+wsSlug+" successful")
return resp.Name, nil
}
func (cl *Client) createGroup(c context.Context, wsSlug string, description string) (string, error) {
resp, err := cl.identityClient.Groups.Create(&cloudidentity.Group{
GroupKey: &cloudidentity.EntityKey{
Id: "workspaces-" + wsSlug + "@nozzle.app",
},
DisplayName: wsSlug,
Description: description,
Parent: groupParent,
Labels: map[string]string{
"cloudidentity.googleapis.com/discussion_forums": "",
},
}).Do()
if err != nil {
return "", err
}
return resp.Name, nil
}
// UpsertMember will create a member for a group or update it.
func (cl *Client) UpsertMember(c context.Context, groupKey, name, email string, role MemberRole) error {
log.Debug(c, "upsert member for "+email)
_, err := cl.identityClient.Groups.Memberships.Create("groups/"+groupKey, &cloudidentity.Membership{
Name: name,
PreferredMemberKey: &cloudidentity.EntityKey{
Id: email,
},
Roles: []*cloudidentity.MembershipRole{{
Name: string(role),
}},
}).Do()
if err != nil {
if gErr, ok := err.(*googleapi.Error); ok {
// group already exists ignore
if gErr.Code == http.StatusConflict {
return nil
}
}
return err
}
log.Debug(c, "upsert member for "+email+" success")
return nil
}
module go.nozzle.io
go 1.15
require (
cloud.google.com/go v0.67.0
cloud.google.com/go/bigquery v1.11.2
cloud.google.com/go/firestore v1.3.0 // indirect
// Don't upgrade this until there is a fix for etcd and grpc
cloud.google.com/go/logging v1.0.0
cloud.google.com/go/pubsub v1.8.0
cloud.google.com/go/storage v1.12.0
contrib.go.opencensus.io/exporter/prometheus v0.2.0
contrib.go.opencensus.io/exporter/stackdriver v0.13.4
contrib.go.opencensus.io/integrations/ocsql v0.1.6
firebase.google.com/go v3.13.0+incompatible
github.com/DATA-DOG/go-sqlmock v1.5.0
// There is an issue with upgrading this do to their use of the kubernetes api
github.com/argoproj/argo-rollouts v0.7.2
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
github.com/cloudflare/cloudflare-go v0.13.3
// Becareful upgrading
github.com/coreos/prometheus-operator v0.38.0
github.com/davecgh/go-spew v1.1.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
// Some tests need this to remain pinned to this version
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2
github.com/dimfeld/httptreemux v5.0.1+incompatible
github.com/dustin/go-humanize v1.0.0
github.com/getsentry/raven-go v0.2.0
github.com/ghodss/yaml v1.0.0
github.com/go-chi/chi v4.1.2+incompatible
// Pinned to v0.1.0 for now because of breaking api change that affects zapr
github.com/go-logr/logr v0.1.0
github.com/go-openapi/swag v0.19.9 // indirect
github.com/go-sql-driver/mysql v1.5.0
github.com/golang/geo v0.0.0-20200730024412-e86565bf3f35
github.com/golang/protobuf v1.4.2
github.com/google/go-github v17.0.0+incompatible
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75
// Upgrading may be an inssue
github.com/grpc-ecosystem/grpc-gateway v1.12.1
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/josephbergevin/strcase v0.0.0-20180315164216-78ac914e4242
github.com/json-iterator/go v1.1.10
github.com/klauspost/compress v1.11.0 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/mitchellh/hashstructure v1.0.0
github.com/ngrok/sqlmw v0.0.0-20200129213757-d5c93a81bec6
github.com/nozzle/fetcher v0.0.0-20200602204932-612c04bfcd4c
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481
github.com/olekukonko/tablewriter v0.0.4
github.com/onsi/ginkgo v1.14.1
github.com/onsi/gomega v1.10.2
github.com/patrickmn/go-cache v0.0.0-20180527043350-9f6ff22cfff8
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.7.1 // indirect
github.com/pusher/pusher-http-go v4.0.1+incompatible
github.com/renstrom/shortuuid v3.0.0+incompatible
github.com/robfig/cron v1.2.0
github.com/sanity-io/litter v1.3.0
github.com/satori/go.uuid v1.2.0
github.com/sendgrid/rest v2.6.1+incompatible // indirect
github.com/sendgrid/sendgrid-go v3.6.4+incompatible
github.com/sergi/go-diff v1.1.0
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.6.1
github.com/stripe/stripe-go v70.15.0+incompatible
github.com/stripe/stripe-go/v71 v71.48.0
github.com/teambition/rrule-go v1.6.0
github.com/testcontainers/testcontainers-go v0.9.0
github.com/ugorji/go/codec v1.1.9
go.opencensus.io v0.22.4
golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
golang.org/x/text v0.3.3
google.golang.org/api v0.32.0
google.golang.org/appengine v1.6.6
google.golang.org/genproto v0.0.0-20201001141541-efaab9d3c4f7
google.golang.org/grpc v1.32.0
gopkg.in/fatih/set.v0 v0.2.1
gopkg.in/yaml.v2 v2.3.0
// Upgrading may be an issue
k8s.io/api v0.18.6
// Upgrading may be an issue
k8s.io/apimachinery v0.18.6
k8s.io/client-go v12.0.0+incompatible
sigs.k8s.io/controller-runtime v0.6.0
// Upgrading may be an issue
vitess.io/vitess v0.0.0-20200225161936-ad4e47a2dbcd
)
replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.5.0
replace k8s.io/client-go => k8s.io/client-go v0.18.2
replace cloud.google.com/go/logging => cloud.google.com/go/logging v1.1.0
replace google.golang.org/grpc => google.golang.org/grpc v1.29.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment