terraform-provider-docker/internal/provider/resource_docker_registry_image_funcs.go

584 lines
19 KiB
Go
Raw Normal View History

package provider
2020-03-24 10:34:14 -04:00
import (
"archive/tar"
"bufio"
"context"
"crypto/sha256"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
2020-03-24 10:34:14 -04:00
"github.com/docker/cli/cli/command/image/build"
2020-03-24 10:34:14 -04:00
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/fileutils"
2020-03-24 10:34:14 -04:00
"github.com/docker/go-units"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2020-03-24 10:34:14 -04:00
)
func resourceDockerRegistryImageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*ProviderConfig).DockerClient
providerConfig := meta.(*ProviderConfig)
name := d.Get("name").(string)
log.Printf("[DEBUG] Creating docker image %s", name)
pushOpts := createPushImageOptions(name)
if buildOptions, ok := d.GetOk("build"); ok {
buildOptionsMap := buildOptions.([]interface{})[0].(map[string]interface{})
err := buildDockerRegistryImage(ctx, client, buildOptionsMap, pushOpts.FqName)
if err != nil {
return diag.Errorf("Error building docker image: %s", err)
}
}
username, password := getDockerRegistryImageRegistryUserNameAndPassword(pushOpts, providerConfig)
if err := pushDockerRegistryImage(ctx, client, pushOpts, username, password); err != nil {
return diag.Errorf("Error pushing docker image: %s", err)
}
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
insecureSkipVerify := d.Get("insecure_skip_verify").(bool)
digest, err := getImageDigestWithFallback(pushOpts, username, password, insecureSkipVerify)
if err != nil {
return diag.Errorf("Unable to create image, image not found: %s", err)
}
d.SetId(digest)
d.Set("sha256_digest", digest)
return nil
}
func resourceDockerRegistryImageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
providerConfig := meta.(*ProviderConfig)
name := d.Get("name").(string)
pushOpts := createPushImageOptions(name)
username, password := getDockerRegistryImageRegistryUserNameAndPassword(pushOpts, providerConfig)
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
insecureSkipVerify := d.Get("insecure_skip_verify").(bool)
digest, err := getImageDigestWithFallback(pushOpts, username, password, insecureSkipVerify)
if err != nil {
log.Printf("Got error getting registry image digest: %s", err)
d.SetId("")
return nil
}
d.Set("sha256_digest", digest)
return nil
}
func resourceDockerRegistryImageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
if d.Get("keep_remotely").(bool) {
return nil
}
providerConfig := meta.(*ProviderConfig)
name := d.Get("name").(string)
pushOpts := createPushImageOptions(name)
username, password := getDockerRegistryImageRegistryUserNameAndPassword(pushOpts, providerConfig)
digest := d.Get("sha256_digest").(string)
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
err := deleteDockerRegistryImage(pushOpts, digest, username, password, true, false)
if err != nil {
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
err = deleteDockerRegistryImage(pushOpts, pushOpts.Tag, username, password, true, true)
if err != nil {
return diag.Errorf("Got error deleting registry image: %s", err)
}
}
return nil
}
func resourceDockerRegistryImageUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return resourceDockerRegistryImageRead(ctx, d, meta)
}
// Helpers
2020-03-24 10:34:14 -04:00
type internalPushImageOptions struct {
Name string
FqName string
Registry string
NormalizedRegistry string
Repository string
Tag string
}
func createImageBuildOptions(buildOptions map[string]interface{}) types.ImageBuildOptions {
mapOfInterfacesToMapOfStrings := func(mapOfInterfaces map[string]interface{}) map[string]string {
mapOfStrings := make(map[string]string, len(mapOfInterfaces))
for k, v := range mapOfInterfaces {
mapOfStrings[k] = fmt.Sprintf("%v", v)
}
return mapOfStrings
}
interfaceArrayToStringArray := func(interfaceArray []interface{}) []string {
stringArray := make([]string, len(interfaceArray))
for i, v := range interfaceArray {
stringArray[i] = fmt.Sprintf("%v", v)
}
return stringArray
}
mapToBuildArgs := func(buildArgsOptions map[string]interface{}) map[string]*string {
buildArgs := make(map[string]*string, len(buildArgsOptions))
for k, v := range buildArgsOptions {
value := v.(string)
buildArgs[k] = &value
}
return buildArgs
}
readULimits := func(options []interface{}) []*units.Ulimit {
ulimits := make([]*units.Ulimit, len(options))
for i, v := range options {
ulimitOption := v.(map[string]interface{})
ulimit := units.Ulimit{
Name: ulimitOption["name"].(string),
Hard: int64(ulimitOption["hard"].(int)),
Soft: int64(ulimitOption["soft"].(int)),
}
ulimits[i] = &ulimit
}
return ulimits
}
readAuthConfigs := func(options []interface{}) map[string]types.AuthConfig {
authConfigs := make(map[string]types.AuthConfig, len(options))
for _, v := range options {
authOptions := v.(map[string]interface{})
auth := types.AuthConfig{
Username: authOptions["user_name"].(string),
Password: authOptions["password"].(string),
Auth: authOptions["auth"].(string),
Email: authOptions["email"].(string),
ServerAddress: authOptions["server_address"].(string),
IdentityToken: authOptions["identity_token"].(string),
RegistryToken: authOptions["registry_token"].(string),
}
authConfigs[authOptions["host_name"].(string)] = auth
}
return authConfigs
}
buildImageOptions := types.ImageBuildOptions{}
buildImageOptions.SuppressOutput = buildOptions["suppress_output"].(bool)
buildImageOptions.RemoteContext = buildOptions["remote_context"].(string)
buildImageOptions.NoCache = buildOptions["no_cache"].(bool)
buildImageOptions.Remove = buildOptions["remove"].(bool)
buildImageOptions.ForceRemove = buildOptions["force_remove"].(bool)
buildImageOptions.PullParent = buildOptions["pull_parent"].(bool)
buildImageOptions.Isolation = container.Isolation(buildOptions["isolation"].(string))
buildImageOptions.CPUSetCPUs = buildOptions["cpu_set_cpus"].(string)
buildImageOptions.CPUSetMems = buildOptions["cpu_set_mems"].(string)
buildImageOptions.CPUShares = int64(buildOptions["cpu_shares"].(int))
buildImageOptions.CPUQuota = int64(buildOptions["cpu_quota"].(int))
buildImageOptions.CPUPeriod = int64(buildOptions["cpu_period"].(int))
buildImageOptions.Memory = int64(buildOptions["memory"].(int))
buildImageOptions.MemorySwap = int64(buildOptions["memory_swap"].(int))
buildImageOptions.CgroupParent = buildOptions["cgroup_parent"].(string)
buildImageOptions.NetworkMode = buildOptions["network_mode"].(string)
buildImageOptions.ShmSize = int64(buildOptions["shm_size"].(int))
buildImageOptions.Dockerfile = buildOptions["dockerfile"].(string)
buildImageOptions.Ulimits = readULimits(buildOptions["ulimit"].([]interface{}))
buildImageOptions.BuildArgs = mapToBuildArgs(buildOptions["build_args"].(map[string]interface{}))
buildImageOptions.AuthConfigs = readAuthConfigs(buildOptions["auth_config"].([]interface{}))
buildImageOptions.Labels = mapOfInterfacesToMapOfStrings(buildOptions["labels"].(map[string]interface{}))
buildImageOptions.Squash = buildOptions["squash"].(bool)
buildImageOptions.CacheFrom = interfaceArrayToStringArray(buildOptions["cache_from"].([]interface{}))
buildImageOptions.SecurityOpt = interfaceArrayToStringArray(buildOptions["security_opt"].([]interface{}))
buildImageOptions.ExtraHosts = interfaceArrayToStringArray(buildOptions["extra_hosts"].([]interface{}))
buildImageOptions.Target = buildOptions["target"].(string)
buildImageOptions.SessionID = buildOptions["session_id"].(string)
buildImageOptions.Platform = buildOptions["platform"].(string)
buildImageOptions.Version = types.BuilderVersion(buildOptions["version"].(string))
buildImageOptions.BuildID = buildOptions["build_id"].(string)
// outputs
return buildImageOptions
}
func buildDockerRegistryImage(ctx context.Context, client *client.Client, buildOptions map[string]interface{}, fqName string) error {
2020-03-25 16:54:04 -04:00
type ErrorDetailMessage struct {
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
type BuildImageResponseMessage struct {
Error string `json:"error,omitempty"`
ErrorDetail *ErrorDetailMessage `json:"errorDetail,omitempty"`
}
getError := func(body io.ReadCloser) error {
dec := json.NewDecoder(body)
for {
message := BuildImageResponseMessage{}
if err := dec.Decode(&message); err != nil {
if err == io.EOF {
break
}
return err
}
if message.ErrorDetail != nil {
detail := message.ErrorDetail
return fmt.Errorf("%v: %s", detail.Code, detail.Message)
}
if len(message.Error) > 0 {
return fmt.Errorf("%s", message.Error)
}
}
return nil
}
2020-03-24 10:34:14 -04:00
log.Printf("[DEBUG] Building docker image")
imageBuildOptions := createImageBuildOptions(buildOptions)
imageBuildOptions.Tags = []string{fqName}
// the tar hash is passed only after the initial creation
buildContext := buildOptions["context"].(string)
if lastIndex := strings.LastIndexByte(buildContext, ':'); (lastIndex > -1) && (buildContext[lastIndex+1] != filepath.Separator) {
2020-03-24 10:34:14 -04:00
buildContext = buildContext[:lastIndex]
}
enableBuildKitIfSupported(ctx, client, &imageBuildOptions)
buildCtx, relDockerfile, err := prepareBuildContext(buildContext, imageBuildOptions.Dockerfile)
if err != nil {
return err
}
imageBuildOptions.Dockerfile = relDockerfile
buildResponse, err := client.ImageBuild(ctx, buildCtx, imageBuildOptions)
if err != nil {
return fmt.Errorf("unable to build image for docker_registry_image: %v", err)
2020-03-24 10:34:14 -04:00
}
defer buildResponse.Body.Close()
2020-03-25 16:54:04 -04:00
err = getError(buildResponse.Body)
2020-03-24 10:34:14 -04:00
if err != nil {
return err
}
return nil
}
func buildDockerImageContextTar(buildContext string) (string, error) {
// Create our Temp File: This will create a filename like /tmp/terraform-provider-docker-123456.tar
tmpFile, err := ioutil.TempFile(os.TempDir(), "terraform-provider-docker-*.tar")
if err != nil {
feat/doc generation (#193) * chore: add tfplugindocs tool * feat: add tfplugin doc dependency and make target * chore: apply documentation generation * docs(contributing): update for documentation generation * fix: adapt website-lint target to new do folder * docs(network): update ds descriptions * docs: add template for index.md * docs: add network resource generation * chore(ci): updates paths for website checks * docs: add plugin data source generation * docs: add import cmd for network resource * docs: add plugin resource generation * feat: outlines remaining resources with example and import cmd * feat: add descriptions to docs * chore: add DevSkim ignores and fix capitalized errors * docs: complete ds registry image * docs: add container resource generation * docs: add lables description to missing resources * docs: remove computed:true from network data so the list is rendered in the description * Revert "docs: remove computed:true from network data" This reverts commit dce9b7a5a23dd8b4156bf6e33947225b5f719df2. * docs: add docker image descriptions to generate the docs * docs: add docker registry image descriptions to generate the docs * docs: add docker service descriptions to generate the docs * docs: add docker volume descriptions to generate the docs * docs(index): clarifies description so more docker resources are mentioned * docs(network): fixes required and read-only attributes so the ds can only be read by-name * docs(plugin): clarifies the ds docs attributes * docs: fix typo registry image ds * docs(config): clarifies attributes and enhances examples Provide a long example and import command * fix(config): make data non-sensitive Because only secrets data is * docs(containter): clarifies attributes and enhances examples with import * docs(config): fix typo * docs(image): clarifies attributes and remove import * docs(network): clarifies attributes and adapts import * docs(plugin): clarifies attributes and import * docs(registry_image): clarifies attributes and removes import * chore(secret): remove typo * docs(service): clarifies attributes and import * docs(volume): clarifies attributes and import * fix: correct md linter rules after doc gen * docs(volume): regenerated * docs: add config custom template * docs: add templates for all resources * docs(config): templates all sections and examples for better redability and structure * docs(config): fix md linter * docs(container): templates all sections and examples * docs(image): templates all sections and examples * docs(image): fix import resource by renaming * docs(network): templates all sections and examples * docs(service): templates all sections and examples * docs(volume): templates all sections and examples * fix(lint): replace website with doc directory * fix(ci): link check file extension check * fix: markdown links * chore: remove old website folder * chore: fix website-lint terrafmr dir and pattern * fix: lint fix target website folder * fix: website links * docs(provider): update examples with templates on auth and certs * docs(provider): add tf-plugin-docs line * docs(contributing): split doc generation section * docs: final brush up for readability and structure * chore(ci): add website-generation job to see if files changed and it should run locally again * chore(ci): remove explicit docker setup from website lint because it's installed by default
2021-05-21 08:30:56 -04:00
return "", fmt.Errorf("cannot create temporary file - %v", err.Error())
2020-03-24 10:34:14 -04:00
}
defer tmpFile.Close()
if _, err = os.Stat(buildContext); err != nil {
feat/doc generation (#193) * chore: add tfplugindocs tool * feat: add tfplugin doc dependency and make target * chore: apply documentation generation * docs(contributing): update for documentation generation * fix: adapt website-lint target to new do folder * docs(network): update ds descriptions * docs: add template for index.md * docs: add network resource generation * chore(ci): updates paths for website checks * docs: add plugin data source generation * docs: add import cmd for network resource * docs: add plugin resource generation * feat: outlines remaining resources with example and import cmd * feat: add descriptions to docs * chore: add DevSkim ignores and fix capitalized errors * docs: complete ds registry image * docs: add container resource generation * docs: add lables description to missing resources * docs: remove computed:true from network data so the list is rendered in the description * Revert "docs: remove computed:true from network data" This reverts commit dce9b7a5a23dd8b4156bf6e33947225b5f719df2. * docs: add docker image descriptions to generate the docs * docs: add docker registry image descriptions to generate the docs * docs: add docker service descriptions to generate the docs * docs: add docker volume descriptions to generate the docs * docs(index): clarifies description so more docker resources are mentioned * docs(network): fixes required and read-only attributes so the ds can only be read by-name * docs(plugin): clarifies the ds docs attributes * docs: fix typo registry image ds * docs(config): clarifies attributes and enhances examples Provide a long example and import command * fix(config): make data non-sensitive Because only secrets data is * docs(containter): clarifies attributes and enhances examples with import * docs(config): fix typo * docs(image): clarifies attributes and remove import * docs(network): clarifies attributes and adapts import * docs(plugin): clarifies attributes and import * docs(registry_image): clarifies attributes and removes import * chore(secret): remove typo * docs(service): clarifies attributes and import * docs(volume): clarifies attributes and import * fix: correct md linter rules after doc gen * docs(volume): regenerated * docs: add config custom template * docs: add templates for all resources * docs(config): templates all sections and examples for better redability and structure * docs(config): fix md linter * docs(container): templates all sections and examples * docs(image): templates all sections and examples * docs(image): fix import resource by renaming * docs(network): templates all sections and examples * docs(service): templates all sections and examples * docs(volume): templates all sections and examples * fix(lint): replace website with doc directory * fix(ci): link check file extension check * fix: markdown links * chore: remove old website folder * chore: fix website-lint terrafmr dir and pattern * fix: lint fix target website folder * fix: website links * docs(provider): update examples with templates on auth and certs * docs(provider): add tf-plugin-docs line * docs(contributing): split doc generation section * docs: final brush up for readability and structure * chore(ci): add website-generation job to see if files changed and it should run locally again * chore(ci): remove explicit docker setup from website lint because it's installed by default
2021-05-21 08:30:56 -04:00
return "", fmt.Errorf("unable to read build context - %v", err.Error())
2020-03-24 10:34:14 -04:00
}
excludes, err := build.ReadDockerignore(buildContext)
if err != nil {
return "", fmt.Errorf("unable to read .dockerignore file - %v", err.Error())
}
pm, err := fileutils.NewPatternMatcher(excludes)
if err != nil {
return "", fmt.Errorf("unable to create pattern matcher from .dockerignore excludes - %v", err.Error())
}
2020-03-24 10:34:14 -04:00
tw := tar.NewWriter(tmpFile)
defer tw.Close()
if err := filepath.Walk(buildContext, func(file string, info os.FileInfo, err error) error {
2020-03-24 10:34:14 -04:00
// return on any error
if err != nil {
return err
}
// if .dockerignore is present, ignore files from there
rel, _ := filepath.Rel(buildContext, file)
skip, err := pm.Matches(rel)
if err != nil {
return err
}
// adapted from https://github.com/moby/moby/blob/v20.10.7/pkg/archive/archive.go#L851
if skip {
log.Printf("[DEBUG] Skipping file/dir from image build '%v'", file)
// If we want to skip this file and its a directory
// then we should first check to see if there's an
// excludes pattern (e.g. !dir/file) that starts with this
// dir. If so then we can't skip this dir.
// Its not a dir then so we can just return/skip.
if !info.IsDir() {
return nil
}
// No exceptions (!...) in patterns so just skip dir
if !pm.Exclusions() {
return filepath.SkipDir
}
dirSlash := file + string(filepath.Separator)
for _, pat := range pm.Patterns() {
if !pat.Exclusion() {
continue
}
if strings.HasPrefix(pat.String()+string(filepath.Separator), dirSlash) {
// found a match - so can't skip this dir
return nil
}
}
// No matching exclusion dir so just skip dir
return filepath.SkipDir
}
2020-03-24 10:34:14 -04:00
// create a new dir/file header
header, err := tar.FileInfoHeader(info, info.Name())
if err != nil {
return err
}
// update the name to correctly reflect the desired destination when untaring
header.Name = strings.TrimPrefix(strings.Replace(file, buildContext, "", -1), string(filepath.Separator))
// set archive metadata non deterministic
header.Mode = 0
header.Uid = 0
header.Gid = 0
header.Uname = ""
header.Gname = ""
header.ModTime = time.Time{}
header.AccessTime = time.Time{}
header.ChangeTime = time.Time{}
2020-03-24 10:34:14 -04:00
// write the header
if err := tw.WriteHeader(header); err != nil {
return err
}
// return on non-regular files (thanks to [kumo](https://medium.com/@komuw/just-like-you-did-fbdd7df829d3) for this suggested update)
if !info.Mode().IsRegular() {
return nil
}
// open files for taring
f, err := os.Open(file)
if err != nil {
return err
}
// copy file data into tar writer
if _, err := io.Copy(tw, f); err != nil {
return err
}
// manually close here after each file operation; defering would cause each file close
// to wait until all operations have completed.
f.Close()
return nil
}); err != nil {
return "", err
}
2020-03-24 10:34:14 -04:00
return tmpFile.Name(), nil
}
func getDockerImageContextTarHash(dockerContextTarPath string) (string, error) {
hasher := sha256.New()
s, err := ioutil.ReadFile(dockerContextTarPath)
if err != nil {
return "", err
}
if _, err := hasher.Write(s); err != nil {
return "", err
}
2020-03-24 10:34:14 -04:00
contextHash := hex.EncodeToString(hasher.Sum(nil))
return contextHash, nil
}
func pushDockerRegistryImage(ctx context.Context, client *client.Client, pushOpts internalPushImageOptions, username string, password string) error {
2020-03-24 10:34:14 -04:00
pushOptions := types.ImagePushOptions{}
if username != "" {
auth := types.AuthConfig{Username: username, Password: password}
authBytes, err := json.Marshal(auth)
if err != nil {
return fmt.Errorf("Error creating push options: %s", err)
}
authBase64 := base64.URLEncoding.EncodeToString(authBytes)
pushOptions.RegistryAuth = authBase64
}
out, err := client.ImagePush(ctx, pushOpts.FqName, pushOptions)
2020-03-24 10:34:14 -04:00
if err != nil {
return err
}
defer out.Close()
type ErrorMessage struct {
Error string
}
var errorMessage ErrorMessage
buffIOReader := bufio.NewReader(out)
for {
streamBytes, err := buffIOReader.ReadBytes('\n')
if err == io.EOF {
break
}
if err := json.Unmarshal(streamBytes, &errorMessage); err != nil {
return err
}
2020-03-24 10:34:14 -04:00
if errorMessage.Error != "" {
return fmt.Errorf("Error pushing image: %s", errorMessage.Error)
}
}
log.Printf("[DEBUG] Pushed image: %s", pushOpts.FqName)
return nil
}
func getDockerRegistryImageRegistryUserNameAndPassword(
pushOpts internalPushImageOptions,
providerConfig *ProviderConfig) (string, string) {
registry := pushOpts.NormalizedRegistry
username := ""
password := ""
if authConfig, ok := providerConfig.AuthConfigs.Configs[registry]; ok {
username = authConfig.Username
password = authConfig.Password
}
return username, password
}
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
func deleteDockerRegistryImage(pushOpts internalPushImageOptions, sha256Digest, username, password string, insecureSkipVerify, fallback bool) error {
2020-03-24 10:34:14 -04:00
client := http.DefaultClient
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
// DevSkim: ignore DS440000
client.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}}
2020-03-24 10:34:14 -04:00
req, err := http.NewRequest("DELETE", pushOpts.NormalizedRegistry+"/v2/"+pushOpts.Repository+"/manifests/"+sha256Digest, nil)
if err != nil {
return fmt.Errorf("Error deleting registry image: %s", err)
}
if username != "" {
req.SetBasicAuth(username, password)
}
// We accept schema v2 manifests and manifest lists, and also OCI types
req.Header.Add("Accept", "application/vnd.docker.distribution.manifest.v2+json")
req.Header.Add("Accept", "application/vnd.docker.distribution.manifest.list.v2+json")
req.Header.Add("Accept", "application/vnd.oci.image.manifest.v1+json")
req.Header.Add("Accept", "application/vnd.oci.image.index.v1+json")
2020-03-24 10:34:14 -04:00
if fallback {
// Fallback to this header if the registry does not support the v2 manifest like gcr.io
req.Header.Set("Accept", "application/vnd.docker.distribution.manifest.v1+prettyjws")
}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("Error during registry request: %s", err)
}
switch resp.StatusCode {
// Basic auth was valid or not needed
case http.StatusOK, http.StatusAccepted, http.StatusNotFound:
return nil
// Either OAuth is required or the basic auth creds were invalid
case http.StatusUnauthorized:
if strings.HasPrefix(resp.Header.Get("www-authenticate"), "Bearer") {
auth := parseAuthHeader(resp.Header.Get("www-authenticate"))
params := url.Values{}
params.Set("service", auth["service"])
params.Set("scope", auth["scope"])
tokenRequest, err := http.NewRequest("GET", auth["realm"]+"?"+params.Encode(), nil)
if err != nil {
return fmt.Errorf("Error creating registry request: %s", err)
}
if username != "" {
tokenRequest.SetBasicAuth(username, password)
}
tokenResponse, err := client.Do(tokenRequest)
if err != nil {
return fmt.Errorf("Error during registry request: %s", err)
}
if tokenResponse.StatusCode != http.StatusOK {
return fmt.Errorf("Got bad response from registry: " + tokenResponse.Status)
}
body, err := ioutil.ReadAll(tokenResponse.Body)
if err != nil {
return fmt.Errorf("Error reading response body: %s", err)
}
token := &TokenResponse{}
err = json.Unmarshal(body, token)
if err != nil {
return fmt.Errorf("Error parsing OAuth token response: %s", err)
}
req.Header.Set("Authorization", "Bearer "+token.Token)
oauthResp, err := client.Do(req)
if err != nil {
return err
}
2020-03-24 10:34:14 -04:00
switch oauthResp.StatusCode {
case http.StatusOK, http.StatusAccepted, http.StatusNotFound:
return nil
default:
return fmt.Errorf("Got bad response from registry: " + resp.Status)
}
}
return fmt.Errorf("Bad credentials: " + resp.Status)
// Some unexpected status was given, return an error
default:
return fmt.Errorf("Got bad response from registry: " + resp.Status)
}
}
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
func getImageDigestWithFallback(opts internalPushImageOptions, username, password string, insecureSkipVerify bool) (string, error) {
digest, err := getImageDigest(opts.Registry, opts.Repository, opts.Tag, username, password, insecureSkipVerify, false)
2020-03-24 10:34:14 -04:00
if err != nil {
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
digest, err = getImageDigest(opts.Registry, opts.Repository, opts.Tag, username, password, insecureSkipVerify, true)
2020-03-24 10:34:14 -04:00
if err != nil {
feat/doc generation (#193) * chore: add tfplugindocs tool * feat: add tfplugin doc dependency and make target * chore: apply documentation generation * docs(contributing): update for documentation generation * fix: adapt website-lint target to new do folder * docs(network): update ds descriptions * docs: add template for index.md * docs: add network resource generation * chore(ci): updates paths for website checks * docs: add plugin data source generation * docs: add import cmd for network resource * docs: add plugin resource generation * feat: outlines remaining resources with example and import cmd * feat: add descriptions to docs * chore: add DevSkim ignores and fix capitalized errors * docs: complete ds registry image * docs: add container resource generation * docs: add lables description to missing resources * docs: remove computed:true from network data so the list is rendered in the description * Revert "docs: remove computed:true from network data" This reverts commit dce9b7a5a23dd8b4156bf6e33947225b5f719df2. * docs: add docker image descriptions to generate the docs * docs: add docker registry image descriptions to generate the docs * docs: add docker service descriptions to generate the docs * docs: add docker volume descriptions to generate the docs * docs(index): clarifies description so more docker resources are mentioned * docs(network): fixes required and read-only attributes so the ds can only be read by-name * docs(plugin): clarifies the ds docs attributes * docs: fix typo registry image ds * docs(config): clarifies attributes and enhances examples Provide a long example and import command * fix(config): make data non-sensitive Because only secrets data is * docs(containter): clarifies attributes and enhances examples with import * docs(config): fix typo * docs(image): clarifies attributes and remove import * docs(network): clarifies attributes and adapts import * docs(plugin): clarifies attributes and import * docs(registry_image): clarifies attributes and removes import * chore(secret): remove typo * docs(service): clarifies attributes and import * docs(volume): clarifies attributes and import * fix: correct md linter rules after doc gen * docs(volume): regenerated * docs: add config custom template * docs: add templates for all resources * docs(config): templates all sections and examples for better redability and structure * docs(config): fix md linter * docs(container): templates all sections and examples * docs(image): templates all sections and examples * docs(image): fix import resource by renaming * docs(network): templates all sections and examples * docs(service): templates all sections and examples * docs(volume): templates all sections and examples * fix(lint): replace website with doc directory * fix(ci): link check file extension check * fix: markdown links * chore: remove old website folder * chore: fix website-lint terrafmr dir and pattern * fix: lint fix target website folder * fix: website links * docs(provider): update examples with templates on auth and certs * docs(provider): add tf-plugin-docs line * docs(contributing): split doc generation section * docs: final brush up for readability and structure * chore(ci): add website-generation job to see if files changed and it should run locally again * chore(ci): remove explicit docker setup from website lint because it's installed by default
2021-05-21 08:30:56 -04:00
return "", fmt.Errorf("unable to get digest: %s", err)
2020-03-24 10:34:14 -04:00
}
}
return digest, nil
}
func createPushImageOptions(image string) internalPushImageOptions {
pullOpts := parseImageOptions(image)
if pullOpts.Registry == "" {
pullOpts.Registry = "registry-1.docker.io"
2020-03-24 10:34:14 -04:00
} else {
pullOpts.Repository = strings.Replace(pullOpts.Repository, pullOpts.Registry+"/", "", 1)
}
pushOpts := internalPushImageOptions{
Name: image,
Registry: pullOpts.Registry,
NormalizedRegistry: normalizeRegistryAddress(pullOpts.Registry),
Repository: pullOpts.Repository,
Tag: pullOpts.Tag,
FqName: fmt.Sprintf("%s/%s:%s", pullOpts.Registry, pullOpts.Repository, pullOpts.Tag),
}
return pushOpts
}