-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added base repo scaffolding (#2)
- Loading branch information
Showing
23 changed files
with
1,362 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
; https://editorconfig.org/ | ||
|
||
root = true | ||
|
||
[*] | ||
charset = utf-8 | ||
indent_size = 2 | ||
indent_style = space | ||
insert_final_newline = true | ||
trim_trailing_whitespace = true | ||
|
||
[{Makefile,go.mod,go.sum,*.go,.gitmodules}] | ||
indent_size = 4 | ||
indent_style = tab | ||
|
||
[*.md] | ||
indent_size = 4 | ||
trim_trailing_whitespace = false | ||
|
||
eclint_indent_style = unset | ||
|
||
[Dockerfile] | ||
indent_size = 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
run: | ||
# Timeout for analysis, e.g. 30s, 5m. | ||
timeout: 5m | ||
|
||
# Include test files. | ||
tests: true | ||
|
||
issues: | ||
# Set to 0 to not skip any issues. | ||
max-issues-per-linter: 0 | ||
|
||
# Set to 0 to not skip any issues. | ||
max-same-issues: 0 | ||
|
||
output: | ||
# Sort results by: filepath, then line, then column. | ||
sort-results: true | ||
|
||
# Make issues output unique by line. | ||
uniq-by-line: false | ||
|
||
linters: | ||
# Enable specific linter | ||
enable: | ||
# Detect context.Context contained in structs. | ||
- containedctx | ||
# Check whether a function uses a non-inherited context. | ||
- contextcheck | ||
# Find declarations and assignments with too many blank identifiers. | ||
- dogsled | ||
# Check for unchecked errors. | ||
- errcheck | ||
# Find code that will cause problems with the error wrapping scheme. | ||
- errorlint | ||
# Find exporting pointers for loop variables. | ||
- exportloopref | ||
# Inspects source code for security problems. | ||
- gosec | ||
# Check that compiler directives are valid. | ||
- gocheckcompilerdirectives | ||
# Calculate cognitive complexities of functions. | ||
- gocognit | ||
# Find repeated strings that could be replaced by a constant. | ||
- goconst | ||
# Provides functionalities missing from other linters. | ||
- gocritic | ||
# Calculates cyclomatic complexity of a function. | ||
- gocyclo | ||
# Check if comments end with a dot. | ||
- godot | ||
# A stricter replacement for gofmt. | ||
- gofumpt | ||
# GO Magic Number Detector. | ||
- gomnd | ||
# Simplify the code. | ||
- gosimple | ||
# Check for correctness of programs. | ||
- govet | ||
# Detect ineffectual assignments. | ||
- ineffassign | ||
# Correct commonly misspelled English words in source files. | ||
- misspell | ||
# Finds the code that returns nil even if it checks that the error is not nil. | ||
- nilerr | ||
# Checks that there is no simultaneous return of nil error and an invalid value. | ||
- nilnil | ||
# Find incorrect usages of t.Parallel(). | ||
- paralleltest | ||
# Reports direct reads from proto message fields when getters should be used. | ||
- protogetter | ||
# Drop-in replacement of golint. | ||
- revive | ||
# Ensure consistent code style when using log/slog. | ||
- sloglint | ||
# Find bugs and performance issues statically. | ||
- staticcheck | ||
# Checks Go code for unused constants, variables, functions and types. | ||
- unused | ||
# Empty lines linter. | ||
- wsl | ||
|
||
# Setting of specific linters. | ||
linters-settings: | ||
paralleltest: | ||
# Ignore missing calls to `t.Parallel()` and only report incorrect uses of it. | ||
ignore-missing: false | ||
|
||
sloglint: | ||
# Enforce using key-value pairs only (incompatible with attr-only). | ||
kv-only: true | ||
# Enforce a single key naming convention. | ||
key-naming-case: snake |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Copyright 2023 Akamai Technologies, Inc. | ||
# | ||
# 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. | ||
|
||
SHELL := /usr/bin/env bash -o errexit -o pipefail -o nounset | ||
.DEFAULT_GOAL := help | ||
|
||
GO ?= go | ||
ENGINE ?= docker | ||
|
||
VERSION ?= $(shell git rev-parse HEAD) | ||
TOOLCHAIN_VERSION := $(shell sed -En 's/^go (.*)$$/\1/p' go.mod) | ||
|
||
REGISTRY := docker.io | ||
IMAGE := linode/linode-cosi-driver | ||
|
||
CONTAINERFILE ?= Dockerfile | ||
OCI_TAGS += --tag=${REGISTRY}/${IMAGE}:${VERSION} | ||
OCI_BUILDARGS += --build-arg=VERSION=${VERSION} | ||
|
||
LDFLAGS ?= | ||
GOFLAGS ?= | ||
GO_SETTINGS += CGO_ENABLED=0 | ||
|
||
.PHONY: all | ||
all: test build image # Run all targets. | ||
|
||
.PHONY: build | ||
build: clean # Build the binary. | ||
${GO_SETTINGS} ${GO} build \ | ||
${GOFLAGS} \ | ||
-ldflags="${LDFLAGS}" \ | ||
-o ./bin/${NAME} \ | ||
./cmd/linode-cosi-driver | ||
|
||
.PHONY: image | ||
image: clean-image # Build container image. | ||
${ENGINE} build \ | ||
${OCI_TAGS} ${OCI_BUILDARGS} \ | ||
--file=${CONTAINERFILE} \ | ||
--target=runtime \ | ||
. | ||
|
||
.PHONY: test | ||
test: # Run unit tests. | ||
${GO} test ${GOFLAGS} \ | ||
-race \ | ||
-cover -covermode=atomic -coverprofile=coverage.out \ | ||
./... | ||
|
||
.PHONY: e2e | ||
e2e: # Run end to end tests. (FIXME: this is placeholder) | ||
@-echo "this is placeholder" | ||
|
||
.PHONY: clean | ||
clean: # Clean the previous build files. | ||
@rm -rf ./bin | ||
|
||
.PHONY: clean-image | ||
clean-image: # Attempt to remove the old container image builds. | ||
@-${ENGINE} image rm -f $(shell ${ENGINE} image ls -aq ${REGISTRY}/${REPOSITORY}/${NAME}:${VERSION} | xargs -n1 | sort -u | xargs) | ||
|
||
.PHONY: help | ||
help: # Show help for each of the Makefile recipes. | ||
@grep -E '^[a-zA-Z0-9 -]+:.*#' Makefile | while read -r l; do printf "\033[1;32m$$(echo $$l | cut -f 1 -d':')\033[00m:$$(echo $$l | cut -f 2- -d'#')\n"; done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// Copyright 2023 Akamai Technologies, Inc. | ||
// | ||
// 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 main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"log/slog" | ||
"net/url" | ||
"os" | ||
"os/signal" | ||
"sync" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" | ||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery" | ||
"github.com/linode/linode-cosi-driver/pkg/endpoint" | ||
"github.com/linode/linode-cosi-driver/pkg/envflag" | ||
"github.com/linode/linode-cosi-driver/pkg/grpc/handlers" | ||
"github.com/linode/linode-cosi-driver/pkg/grpc/logger" | ||
"github.com/linode/linode-cosi-driver/pkg/servers/identity" | ||
"github.com/linode/linode-cosi-driver/pkg/servers/provisioner" | ||
"google.golang.org/grpc" | ||
cosi "sigs.k8s.io/container-object-storage-interface-spec" | ||
) | ||
|
||
var log *slog.Logger | ||
|
||
const ( | ||
driverName = "objectstorage.cosi.linode.com" | ||
gracePeriod = 5 * time.Second | ||
) | ||
|
||
func main() { | ||
linodeToken := envflag.String("LINODE_TOKEN", "") | ||
linodeURL := envflag.String("LINODE_API_URL", "") | ||
cosiEndpoint := envflag.String("COSI_ENDPOINT", "unix:///var/lib/cosi/cosi.sock") | ||
|
||
// TODO: any logger settup must be done here, before first log call. | ||
log = slog.Default() | ||
|
||
if err := realMain(context.Background(), cosiEndpoint, linodeToken, linodeURL); err != nil { | ||
slog.Error("critical failure", "error", err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func realMain(ctx context.Context, cosiEndpoint, _, _ string) error { | ||
ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) | ||
defer stop() | ||
|
||
// create identity server | ||
idSrv, err := identity.New(driverName) | ||
if err != nil { | ||
return fmt.Errorf("failed to create identity server: %w", err) | ||
} | ||
|
||
// create provisioner server | ||
prvSrv, err := provisioner.New(log) | ||
if err != nil { | ||
return fmt.Errorf("failed to create provisioner server: %w", err) | ||
} | ||
|
||
// parse endpoint | ||
endpointURL, err := url.Parse(cosiEndpoint) | ||
if err != nil { | ||
return fmt.Errorf("unable to parse COSI endpoint: %w", err) | ||
} | ||
|
||
// create the endpoint handler | ||
lis, err := endpoint.New(endpointURL).Listener(ctx) | ||
if err != nil { | ||
return fmt.Errorf("unable to create new listener: %w", err) | ||
} | ||
defer lis.Close() | ||
|
||
// create the grpcServer | ||
srv, err := grpcServer(ctx, idSrv, prvSrv) | ||
if err != nil { | ||
return fmt.Errorf("gRPC server creation failed: %w", err) | ||
} | ||
|
||
var wg sync.WaitGroup | ||
|
||
wg.Add(1) | ||
|
||
go shutdown(ctx, &wg, srv) | ||
|
||
slog.Info("starting server", "endpoint", endpointURL) | ||
|
||
err = srv.Serve(lis) | ||
if err != nil { | ||
return fmt.Errorf("gRPC server failed: %w", err) | ||
} | ||
|
||
wg.Wait() | ||
|
||
return nil | ||
} | ||
|
||
func grpcServer(ctx context.Context, identity cosi.IdentityServer, provisioner cosi.ProvisionerServer) (*grpc.Server, error) { | ||
server := grpc.NewServer( | ||
grpc.ChainUnaryInterceptor( | ||
logging.UnaryServerInterceptor(logger.Wrap(log)), | ||
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(handlers.PanicRecovery(ctx, log))), | ||
), | ||
) | ||
|
||
if identity == nil || provisioner == nil { | ||
return nil, errors.New("provisioner and identity servers cannot be nil") | ||
} | ||
|
||
cosi.RegisterIdentityServer(server, identity) | ||
cosi.RegisterProvisionerServer(server, provisioner) | ||
|
||
return server, nil | ||
} | ||
|
||
// shutdown handles shutdown with grace period consideration. | ||
func shutdown(ctx context.Context, wg *sync.WaitGroup, g *grpc.Server) { | ||
<-ctx.Done() | ||
defer wg.Done() | ||
defer slog.Info("stopped") | ||
|
||
slog.Info("shutting down") | ||
|
||
dctx, stop := context.WithTimeout(context.Background(), gracePeriod) | ||
defer stop() | ||
|
||
c := make(chan struct{}) | ||
|
||
if g != nil { | ||
go func() { | ||
g.GracefulStop() | ||
c <- struct{}{} | ||
}() | ||
|
||
for { | ||
select { | ||
case <-dctx.Done(): | ||
slog.Warn("forcing shutdown") | ||
g.Stop() | ||
|
||
return | ||
case <-c: | ||
return | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2023 Akamai Technologies, Inc. | ||
// | ||
// 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 main_test | ||
|
||
import "testing" | ||
|
||
func TestRealMain(t *testing.T) { | ||
t.Parallel() | ||
|
||
for _, tc := range []struct { | ||
testName string | ||
}{} { | ||
tc := tc | ||
|
||
t.Run(tc.testName, func(t *testing.T) { | ||
t.Parallel() | ||
}) | ||
} | ||
} |
Oops, something went wrong.