Skip to content

Commit

Permalink
Add zero experimental tool
Browse files Browse the repository at this point in the history
  • Loading branch information
timburks committed Oct 13, 2023
1 parent 4b20316 commit bfccd15
Show file tree
Hide file tree
Showing 41 changed files with 3,478 additions and 0 deletions.
113 changes: 113 additions & 0 deletions cmd/zero/DOCUMENTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Zero

Simple API management without a gateway. Instead of using a gateway, we will
make direct calls to service control APIs from within our API server.

Is this a good idea?

Pros:

- simple (no proxies to set up and manage)
- inexpensive (no additional sidecars to operate)
- runs anywhere (even when you run your server locally)

Cons:

- requires changes to your application
- hard to govern, there may be uncontrolled APIs that leak information

## Demonstration

### Preparation

#### You need a domain

To register a service with service manager, a domain is required.

##### Use a domain you control

We can register a domain with a registrar and prove to Google that we own it,
and then we can create services on that domain or any subdomain.
“example1.timbx.me”

##### Get a domain from App Engine

Alternately, we can use Google App Engine to get a domain that we can use. App
Engine apps are hosted at <appname>.appspot.com, where <appname> is usually the
project id.

- create an app engine app for your project
- this will give you “appname.appspot.com”. For example, for my project, named
“nerdvana”, my domain name is “nerdvana.appspot.com”
- we can use this for our service name.
- we can also use subdomains of this domain.

#### Create OAuth credentials

These will be used to call the servicemanagement API

store them in ~/.config/zero/credentials.json

We could also use a service account for this.

#### Set up the CLI

create ~/.config/zero/zero.yaml for general configuration

```
serviceName: nerdvana.appspot.com
serviceConfig: 2023-10-06r1
apiKey: XXX-REDACTED-XXX
producerProject: nerdvana
consumerProject: nerdvana
summary: "Namaste"
title: "Nerdvana"
```

### Service Management

#### Create your service

Create your service with a call to the service management API

View the service in the endpoints console

#### Configure your service

Create your service config -- notice that we want to specify some things:

- name / version
- description
- operations

#### Rollout your configuration

Rollout your service config

Verify the rollout in the endpoints console

### Service Control

Create a service account to call the servicecontrol API

Call the check service

Call the check/allocatequota/report methods

### The Sample API

TODO

## Capabilities and Limitations

TODO

## Using the Service Management API to build an API Catalog

Get a list of managed services and the configurations for each. Each
configuration includes the list of operations that the API supports. These
lists can be used to build an index of APIs being provided by your Google
project.

Not all APIs -- these are just the formally registered ones. Other indicators
of APIs are Load Balancers, Cloud Run endpoints, and GKE ingresses.
25 changes: 25 additions & 0 deletions cmd/zero/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# zero

This directory contains an experimental command-line tool that explores the
[Google Service Infrastructure](https://cloud.google.com/service-infrastructure/docs/overview).

This tool is temporarily named `zero` to indicate that this is a minimalist
effort to explore the Service Infrastructure APIs out of the context of an API
gateway.

Areas to explore include:

- Automatically creating managed services and manage service configurations for
APIs in an API registry.
- Automatically importing information into an API registry from the
[Service Management API](https://cloud.google.com/service-infrastructure/docs/service-management/getting-started).
- Directly calling the
[Service Control API](https://cloud.google.com/service-infrastructure/docs/service-control/getting-started)
as an alternative to using an API proxy for the most basic API management
needs.

Custom components used by the tool are in the `pkg` directory. Implementations
of CLI subcommands are in the `cmd` directory.

Code is published for transparency and community review with no promises of
support or continued existence.
34 changes: 34 additions & 0 deletions cmd/zero/cmd/apikeys/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2023 Google LLC. All Rights Reserved.
//
// Licensed 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 apikeys

import (
"github.com/apigee/registry-experimental/cmd/zero/cmd/apikeys/operations"
"github.com/spf13/cobra"
)

func Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "api-keys",
Short: "API key management",
}
cmd.AddCommand(createCmd())
cmd.AddCommand(deleteCmd())
cmd.AddCommand(getCmd())
cmd.AddCommand(getKeyStringCmd())
cmd.AddCommand(listCmd())
cmd.AddCommand(operations.Cmd())
return cmd
}
73 changes: 73 additions & 0 deletions cmd/zero/cmd/apikeys/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2023 Google LLC. All Rights Reserved.
//
// Licensed 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 apikeys

import (
"context"
"fmt"

"github.com/apigee/registry-experimental/cmd/zero/pkg/config"
"github.com/apigee/registry-experimental/cmd/zero/pkg/patch"
"github.com/spf13/cobra"
"google.golang.org/api/apikeys/v2"
"google.golang.org/api/option"
)

func createCmd() *cobra.Command {
var output string
var producerProject string
cmd := &cobra.Command{
Use: "create KEYID SERVICE",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
client, err := config.GetClient(ctx)
if err != nil {
return err
}
apikey := &apikeys.V2Key{
Restrictions: &apikeys.V2Restrictions{
ApiTargets: []*apikeys.V2ApiTarget{
{Service: args[1]},
},
},
}
srv, err := apikeys.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
return err
}
parent := fmt.Sprintf("projects/%s/locations/global", producerProject)
keyId := args[0]
item, err := apikeys.NewProjectsLocationsKeysService(srv).
Create(parent, apikey).
KeyId(keyId).
Do()
if err != nil {
return err
}
bytes, err := patch.MarshalAndWrap(item, "Operation", item.Name, output)
if err != nil {
return err
}
if _, err := cmd.OutOrStdout().Write(bytes); err != nil {
return err
}
return nil
},
}
cmd.Flags().StringVarP(&output, "output", "o", "yaml", "Output format. One of: (yaml, json).")
cmd.Flags().StringVarP(&producerProject, "project", "p", "", "Producer project.")
return cmd
}
62 changes: 62 additions & 0 deletions cmd/zero/cmd/apikeys/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2023 Google LLC. All Rights Reserved.
//
// Licensed 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 apikeys

import (
"context"

"github.com/apigee/registry-experimental/cmd/zero/pkg/config"
"github.com/apigee/registry-experimental/cmd/zero/pkg/patch"
"google.golang.org/api/apikeys/v2"
"google.golang.org/api/option"

"github.com/spf13/cobra"
)

func deleteCmd() *cobra.Command {
var output string
cmd := &cobra.Command{
Use: "delete APIKEY",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
client, err := config.GetClient(ctx)
if err != nil {
return err
}
apikey := args[0]
srv, err := apikeys.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
return err
}
item, err := apikeys.NewProjectsLocationsKeysService(srv).
Delete(apikey).
Do()
if err != nil {
return err
}
bytes, err := patch.MarshalAndWrap(item, "Operation", item.Name, output)
if err != nil {
return err
}
if _, err := cmd.OutOrStdout().Write(bytes); err != nil {
return err
}
return nil
},
}
cmd.Flags().StringVarP(&output, "output", "o", "yaml", "Output format. One of: (yaml, json).")
return cmd
}
62 changes: 62 additions & 0 deletions cmd/zero/cmd/apikeys/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2023 Google LLC. All Rights Reserved.
//
// Licensed 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 apikeys

import (
"context"

"github.com/apigee/registry-experimental/cmd/zero/pkg/config"
"github.com/apigee/registry-experimental/cmd/zero/pkg/patch"
"google.golang.org/api/apikeys/v2"
"google.golang.org/api/option"

"github.com/spf13/cobra"
)

func getCmd() *cobra.Command {
var output string
cmd := &cobra.Command{
Use: "get APIKEY",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
client, err := config.GetClient(ctx)
if err != nil {
return err
}
apikey := args[0]
srv, err := apikeys.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
return err
}
item, err := apikeys.NewProjectsLocationsKeysService(srv).
Get(apikey).
Do()
if err != nil {
return err
}
bytes, err := patch.MarshalAndWrap(item, "ApiKey", item.Name, output)
if err != nil {
return err
}
if _, err := cmd.OutOrStdout().Write(bytes); err != nil {
return err
}
return nil
},
}
cmd.Flags().StringVarP(&output, "output", "o", "yaml", "Output format. One of: (yaml, json).")
return cmd
}
Loading

0 comments on commit bfccd15

Please sign in to comment.