From 505b8a59406264c49356de270117194e7890a549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20D=C3=ADaz=20Marco?= Date: Sun, 15 Jan 2023 20:03:56 +0100 Subject: [PATCH 1/3] Add containerized development environment. --- .env.example | 2 ++ .gitignore | 2 +- Dockerfile | 42 +++++++++++++++++++++++++++++++++++++++++ Makefile | 35 +++++++++++++++++++++++++--------- README.md | 47 ++++++++++++++++++++++++++++++---------------- docker-compose.yml | 16 ++++++++++++++++ 6 files changed, 118 insertions(+), 26 deletions(-) create mode 100755 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.env.example b/.env.example new file mode 100755 index 0000000000..eed8916673 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +# Docker +#USER_ID=1000 diff --git a/.gitignore b/.gitignore index c8c389c08d..a66885fdbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .DS_Store +.env .gobincache/ - diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..d0368e02ca --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +ARG GO_VERSION=1.19.5 +ARG ALPINE_VERSION=3.17 +ARG GOIMPORTS_VERSION=0.5.0 +ARG DELVE_VERSION=1.20.1 +ARG SWAGGER_VERSION=0.30.3 + + +## Base image +FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base + +WORKDIR /go/src/app + +ENV CGO_ENABLED=0 + + +## Development image +FROM base AS development + +ARG GOIMPORTS_VERSION +ARG DELVE_VERSION +ARG SWAGGER_VERSION + +RUN apk add \ + bash \ + curl \ + git \ + jq \ + python3 \ + zsh \ + && go install golang.org/x/tools/cmd/goimports@v${GOIMPORTS_VERSION} \ + && go install github.com/go-delve/delve/cmd/dlv@v${DELVE_VERSION} \ + && go install github.com/go-swagger/go-swagger/cmd/swagger@v${SWAGGER_VERSION} + +ARG USER_ID=1000 +ENV USER_NAME=default + +ENV PROMPT="%B%F{cyan}%n%f@%m:%F{yellow}%~%f %F{%(?.green.red[%?] )}>%f %b" + +RUN adduser -D -u $USER_ID ${USER_NAME} \ + && chown -R ${USER_NAME}: /go/pkg + +USER ${USER_NAME} diff --git a/Makefile b/Makefile index fcd8872695..38ccc49a84 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,29 @@ -deps: - go mod download - go install github.com/go-swagger/go-swagger/cmd/swagger@latest +# Helpers +IS_DARWIN := $(filter Darwin,$(shell uname -s)) -generate: deps - swagger generate client --target=./netbox --copyright-file=copyright_header.txt +define set_env + sed $(if $(IS_DARWIN),-i "",-i) -e "s/^#*\($(1)=\).*/$(if $(2),,#)\1$(2)/" .env +endef -clean: - rm -rf netbox/client netbox/models +EXEC := docker compose exec app -integration: - go test ./... -tags=integration +# Environment recipes +.PHONY: default +default: init up + +.PHONY: init +init: + test -f .env || cp .env.example .env + $(call set_env,USER_ID,$(shell id -u)) + +.PHONY: up +up: + DOCKER_BUILDKIT=1 docker compose up -d --build + +.PHONY: down +down: + docker compose down + +.PHONY: shell +shell: + $(EXEC) zsh diff --git a/README.md b/README.md index 5ff2826b94..5dad139ac8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -go-netbox -========= +# go-netbox [![GoDoc](http://godoc.org/github.com/netbox-community/go-netbox?status.svg)](http://godoc.org/github.com/netbox-community/go-netbox) [![Build Status](https://github.com/netbox-community/go-netbox/workflows/main/badge.svg?branch=master)](https://github.com/netbox-community/go-netbox/actions) [![Report Card](https://goreportcard.com/badge/github.com/netbox-community/go-netbox)](https://goreportcard.com/report/github.com/netbox-community/go-netbox) @@ -7,8 +6,7 @@ Package `netbox` provides an API 3.2 client for [netbox-community's Netbox](http This package assumes you are using Netbox 3.2, as the Netbox 1.0 API no longer exists. If you need support for previous Netbox versions, you can still import the corresponding release of the library. For example, run `go get github.com/netbox-community/go-netbox@netbox_v2.11` if you need compatibility with Netbox 2.11. -Using the client -================ +## Using the client The `github.com/netbox-community/go-netbox/netbox` package has some convenience functions for creating clients with the most common configurations you are likely to need while connecting to NetBox. `NewNetboxAt` allows you to specify a hostname @@ -68,16 +66,14 @@ func main() { } ``` -Go Module support -================ +## Go Module support Go 1.16+ `go get github.com/netbox-community/go-netbox` -More complex client configuration -================================= +## More complex client configuration The client is generated using [go-swagger](https://github.com/go-swagger/go-swagger). This means the generated client makes use of [github.com/go-openapi/runtime/client](https://godoc.org/github.com/go-openapi/runtime/client). If you need @@ -88,14 +84,33 @@ The [godocs for the go-openapi/runtime/client module](https://godoc.org/github.c the client options in detail, including different authentication and debugging options. One thing I want to flag because it is so useful: setting the `DEBUG` environment variable will dump all requests to standard out. -Regenerating the client -======================= +## Development -To regenerate the client with a new or different swagger schema, first clean the existing client, then replace -swagger.json and finally re-generate: +The project comes with a containerized development environment that can be used from any platform. It is only required to have [Git](https://git-scm.com) and [Docker Desktop](https://www.docker.com/products/docker-desktop/) (or, separately, [Docker](https://docs.docker.com/engine/install) and [Docker Compose](https://docs.docker.com/compose/install/)) installed on the machine. + +To start the development environment, run the following command. + +```bash +make ``` -make clean -./scripts/swagger_modifier.py new_swagger_file.json -mv swagger_transformed.json swagger.json -make generate + +Then, to attach a shell in the container, run the command below. + +```bash +make shell ``` + +Finally, to stop the development environment, run the following command. + +```bash +make down +``` + +### Considerations + +The library is almost entirely generated from the Netbox [OpenAPI](https://www.openapis.org/) specification. Therefore, files under directories `netbox/client` and `netbox/models` should not be directly modified, as they will be overwritten in the next regeneration (see next section). + +To fix issues in generated code, there are two options: + +- Change the OpenAPI spec with pre-generation hooks (see [`scripts/pre-generation`](scripts/pre-generation)). +- If the above is not possible, change the generated code with post-generation hooks (see [`scripts/post-generation`](scripts/post-generation)). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..dc4ee24815 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +services: + app: + build: + context: . + target: development + args: + USER_ID: ${USER_ID:-1000} + volumes: + - .:/go/src/app + - cache:/go/pkg + env_file: .env + hostname: app + tty: true + +volumes: + cache: From eacc757bb5061a8bdb50cf8415c5e932c732db12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20D=C3=ADaz=20Marco?= Date: Sun, 15 Jan 2023 20:21:59 +0100 Subject: [PATCH 2/3] Improve code generation workflow. --- Makefile | 11 +++++ README.md | 20 +++++++++ api/netbox_docker_version | 1 + api/netbox_version | 1 + swagger.json => api/openapi.json | 0 .../copyright_header.txt | 0 scripts/fetch-spec.sh | 26 +++++++++++ scripts/generate-code.sh | 26 +++++++++++ scripts/{licensecheck.sh => license-check.sh} | 0 scripts/post-generation/fix-integers.sh | 18 ++++++++ .../fix-schema.py} | 19 ++------ scripts/set-versions.sh | 43 +++++++++++++++++++ 12 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 api/netbox_docker_version create mode 100644 api/netbox_version rename swagger.json => api/openapi.json (100%) rename copyright_header.txt => assets/copyright_header.txt (100%) create mode 100755 scripts/fetch-spec.sh create mode 100755 scripts/generate-code.sh rename scripts/{licensecheck.sh => license-check.sh} (100%) create mode 100755 scripts/post-generation/fix-integers.sh rename scripts/{swagger_modifier.py => pre-generation/fix-schema.py} (81%) create mode 100755 scripts/set-versions.sh diff --git a/Makefile b/Makefile index 38ccc49a84..2ba9068822 100644 --- a/Makefile +++ b/Makefile @@ -27,3 +27,14 @@ down: .PHONY: shell shell: $(EXEC) zsh + +# Project recipes +.PHONY: build +build: + $(EXEC) ./scripts/set-versions.sh $(NETBOX_VERSION) $(NETBOX_DOCKER_VERSION) + ./scripts/fetch-spec.sh $$(cat api/netbox_version) $$(cat api/netbox_docker_version) + $(EXEC) ./scripts/generate-code.sh + +.PHONY: test +test: + $(EXEC) go test ./... -tags=integration diff --git a/README.md b/README.md index 5dad139ac8..310d1aaa08 100644 --- a/README.md +++ b/README.md @@ -114,3 +114,23 @@ To fix issues in generated code, there are two options: - Change the OpenAPI spec with pre-generation hooks (see [`scripts/pre-generation`](scripts/pre-generation)). - If the above is not possible, change the generated code with post-generation hooks (see [`scripts/post-generation`](scripts/post-generation)). + +### Regenerate the library + +To update the OpenAPI specification to the latest Netbox version and regenerate the library, run the following command. + +```bash +make build +``` + +If regeneration of the library is needed for a specific Netbox version other than the latest one, pass the corresponding argument. + +```bash +make build NETBOX_VERSION=3.0.0 +``` + +In order to obtain the OpenAPI specification, the version of _[netbox-docker](https://github.com/netbox-community/netbox-docker)_ corresponding to the given Netbox version is used. However, it is also possible to provide a specific version of _netbox-docker_. + +```bash +make build NETBOX_VERSION=3.0.0 NETBOX_DOCKER_VERSION=1.3.1 +``` diff --git a/api/netbox_docker_version b/api/netbox_docker_version new file mode 100644 index 0000000000..276cbf9e28 --- /dev/null +++ b/api/netbox_docker_version @@ -0,0 +1 @@ +2.3.0 diff --git a/api/netbox_version b/api/netbox_version new file mode 100644 index 0000000000..5f6fc5edc2 --- /dev/null +++ b/api/netbox_version @@ -0,0 +1 @@ +3.3.10 diff --git a/swagger.json b/api/openapi.json similarity index 100% rename from swagger.json rename to api/openapi.json diff --git a/copyright_header.txt b/assets/copyright_header.txt similarity index 100% rename from copyright_header.txt rename to assets/copyright_header.txt diff --git a/scripts/fetch-spec.sh b/scripts/fetch-spec.sh new file mode 100755 index 0000000000..93fc30089f --- /dev/null +++ b/scripts/fetch-spec.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NETBOX_VERSION="$1" +NETBOX_DOCKER_VERSION="$2" + +REPO_DIR='/tmp/netbox-docker' + +rm -rf "${REPO_DIR}" + +git clone https://github.com/netbox-community/netbox-docker.git \ + --config advice.detachedHead=false \ + --branch ${NETBOX_DOCKER_VERSION} \ + --depth=1 \ + --quiet \ + "${REPO_DIR}" + +mv "${REPO_DIR}/docker-compose.override.yml.example" "${REPO_DIR}/docker-compose.override.yml" + +export VERSION="v${NETBOX_VERSION}" +docker compose --project-directory="${REPO_DIR}" up --detach --quiet-pull + +curl --silent http://127.0.0.1:8000/api/docs/?format=openapi > api/openapi.json + +docker compose --project-directory="${REPO_DIR}" down diff --git a/scripts/generate-code.sh b/scripts/generate-code.sh new file mode 100755 index 0000000000..ff6e0ae6d8 --- /dev/null +++ b/scripts/generate-code.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +export SRC_DIR='./netbox' + +# Prepare environment +rm -rf netbox/client netbox/models +go mod download + +# Run pre-generation hooks +for SCRIPT in scripts/pre-generation/*; do + "${SCRIPT}" +done + +# Generate code +swagger generate client -f api/openapi.json --target="${SRC_DIR}" --copyright-file=assets/copyright_header.txt +go mod tidy + +# Run post-generation hooks +for SCRIPT in scripts/post-generation/*; do + "${SCRIPT}" +done + +# Format generated code and fix imports +goimports -w "${SRC_DIR}" diff --git a/scripts/licensecheck.sh b/scripts/license-check.sh similarity index 100% rename from scripts/licensecheck.sh rename to scripts/license-check.sh diff --git a/scripts/post-generation/fix-integers.sh b/scripts/post-generation/fix-integers.sh new file mode 100755 index 0000000000..24b6f2b2f6 --- /dev/null +++ b/scripts/post-generation/fix-integers.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Maximum and minimum values in spec that correspond to +# `math.MaxInt64` and `math.MinInt64`, respectively, are not rendered +# properly by "go-swagger", thus causing the following errors. +# +# cannot use -9.223372036854776e+18 (untyped float constant -9.22337e+18) as int64 value in argument to validate.MinimumInt (truncated) +# cannot use 9.223372036854776e+18 (untyped float constant 9.22337e+18) as int64 value in argument to validate.MaximumInt (truncated) +# +# See: https://github.com/go-swagger/go-swagger/issues/2755 + +set -euo pipefail + +find "${SRC_DIR}" -type f -name '*.go' -exec \ + sed -i \ + -e 's/-9.223372036854776e+18/math.MinInt64/' \ + -e 's/9.223372036854776e+18/math.MaxInt64/' \ + {} \; diff --git a/scripts/swagger_modifier.py b/scripts/pre-generation/fix-schema.py similarity index 81% rename from scripts/swagger_modifier.py rename to scripts/pre-generation/fix-schema.py index 149e71ea6d..24d75c88c6 100755 --- a/scripts/swagger_modifier.py +++ b/scripts/pre-generation/fix-schema.py @@ -44,7 +44,7 @@ def cli_arguments(): :return: argparse.parser object """ parser = argparse.ArgumentParser( - description=('Modifications on swagger.json.')) + description=('Modifications on openapi.json.')) parser.add_argument('-v', '--verbose', action='count', @@ -52,11 +52,11 @@ def cli_arguments(): help='Increase output verbosity.') parser.add_argument('-o', '--output', - default='swagger_transformed.json', + default='api/openapi.json', help='Output file') parser.add_argument('input', nargs='?', - default='swagger.json', + default='api/openapi.json', help='Original input json file') return parser.parse_args() @@ -124,17 +124,6 @@ def complete_data(input_file, log): def_properties[def_property].update( modify_properties[prop]) - for p in def_properties: - # The maximum value (9223372036854775807) set here lead to an error - # cannot use 9.223372036854776e+18 (untyped float constant 9.22337e+18) as int64 value in argument to validate.MaximumInt (truncated) # noqa E501 - # There's issue opened on this https://github.com/go-swagger/go-swagger/issues/2755 # noqa E501 - if def_properties[p].get('maximum', 0) == 9223372036854775807: - log.info('Changing maximum value for {}'.format(p)) - def_properties[p]['maximum'] = 2147483647 - # The minimum value also has same issue. - if def_properties[p].get('minimum', 0) == -9223372036854775808: - log.info('Changing minimum value for {}'.format(p)) - def_properties[p]['minimum'] = -2147483648 return (data) @@ -160,7 +149,7 @@ def write_results(data, output_file, log): def main(): args = cli_arguments() # Get logger - log = init_logger('swagger', args.verbose, logfile='/tmp/swagger.log') + log = init_logger('openapi', args.verbose, logfile='/tmp/openapi.log') modified_data = complete_data(args.input, log) write_results(modified_data, args.output, log) diff --git a/scripts/set-versions.sh b/scripts/set-versions.sh new file mode 100755 index 0000000000..cf2e86cf14 --- /dev/null +++ b/scripts/set-versions.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +NETBOX_VERSION='latest' +NETBOX_DOCKER_VERSION='auto' + +set -euo pipefail + +# Parse Netbox version +if [ "$#" -gt 0 ]; then + NETBOX_VERSION="$1" +fi + +if [ "${NETBOX_VERSION}" == 'latest' ]; then + NETBOX_VERSION=$(curl --silent https://api.github.com/repos/netbox-community/netbox/releases/latest | + jq '.tag_name' | + sed -E 's/"v([^"]+)"/\1/') +fi + +# Parse Netbox Docker version +if [ "$#" -gt 1 ]; then + NETBOX_DOCKER_VERSION="$2" +fi + +if [ "${NETBOX_DOCKER_VERSION}" == 'auto' ]; then + NEXT='https://registry.hub.docker.com/v2/repositories/netboxcommunity/netbox/tags/?page=1&page_size=1000' + NETBOX_DOCKER_VERSION='' + + while [ "${NEXT}" != "null" ] && [ "${NETBOX_DOCKER_VERSION}" == "" ]; do + RESPONSE=$(curl --silent "${NEXT}") + NEXT=$(echo -E "${RESPONSE}" | jq '.next') + + NETBOX_DOCKER_VERSION=$(echo -E "${RESPONSE}" | + jq -r ".results[] | select(.name | startswith(\"v${NETBOX_VERSION}-\")) | .name" | + cut -d "-" -f 2) + done + + unset NEXT + unset RESPONSE +fi + +# Print variables +echo ${NETBOX_VERSION} > api/netbox_version +echo ${NETBOX_DOCKER_VERSION} > api/netbox_docker_version From 6f8ab2b0138c277da2a8bfd47aa085fd20e37e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20D=C3=ADaz=20Marco?= Date: Sun, 15 Jan 2023 20:58:20 +0100 Subject: [PATCH 3/3] Rename script usage in GitHub workflow. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5bb42acd20..00e5ed19da 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v2 - name: License check - run: ./scripts/licensecheck.sh + run: ./scripts/license-check.sh - name: Go installation uses: actions/setup-go@v2