diff --git a/CHANGELOG.md b/CHANGELOG.md index d702c450f..9ca665e83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,34 @@ +## [v2.6.6](https://github.com/traefik/traefik/tree/v2.6.6) (2022-05-03) +[All Commits](https://github.com/traefik/traefik/compare/v2.6.3...v2.6.6) + +**Bug fixes:** +- **[acme]** Fix RenewInterval computation in ACME provider ([#8969](https://github.com/traefik/traefik/pull/8969) by [smasset-orange](https://github.com/smasset-orange)) +- **[ecs,logs]** Remove duplicate error logs ([#8916](https://github.com/traefik/traefik/pull/8916) by [rtribotte](https://github.com/rtribotte)) +- **[ecs]** Filter out ECS anywhere instance IDs ([#8973](https://github.com/traefik/traefik/pull/8973) by [JohnPreston](https://github.com/JohnPreston)) +- **[middleware]** Re-add missing writeheader call in flush ([#8957](https://github.com/traefik/traefik/pull/8957) by [mpl](https://github.com/mpl)) +- **[middleware]** Fix bug for when custom page is large enough ([#8932](https://github.com/traefik/traefik/pull/8932) by [mpl](https://github.com/mpl)) +- **[middleware]** Fix regexp handling in redirect middleware ([#8920](https://github.com/traefik/traefik/pull/8920) by [tomMoulard](https://github.com/tomMoulard)) +- **[plugins]** Update Yaegi to v0.11.3 ([#8954](https://github.com/traefik/traefik/pull/8954) by [kevinpollet](https://github.com/kevinpollet)) + +**Documentation:** +- **[k8s/gatewayapi]** Fix certificateRefs in dynamic configuration ([#8940](https://github.com/traefik/traefik/pull/8940) by [kahirokunn](https://github.com/kahirokunn)) +- **[logs]** Move accessLog.fields example to TOML section ([#8944](https://github.com/traefik/traefik/pull/8944) by [major](https://github.com/major)) +- **[logs]** Add default mode for fields.names to access log ([#8933](https://github.com/traefik/traefik/pull/8933) by [aleksvujic](https://github.com/aleksvujic)) +- **[middleware]** Fix default for buffering middleware ([#8945](https://github.com/traefik/traefik/pull/8945) by [rtribotte](https://github.com/rtribotte)) +- **[middleware]** Preflight requests are not forwarded to services ([#8923](https://github.com/traefik/traefik/pull/8923) by [sizief](https://github.com/sizief)) +- Add title and description metadata to documentation pages ([#8941](https://github.com/traefik/traefik/pull/8941) by [ldez](https://github.com/ldez)) +- Update dynamic and static configuration references ([#8918](https://github.com/traefik/traefik/pull/8918) by [ldez](https://github.com/ldez)) + +## [v2.6.5](https://github.com/traefik/traefik/tree/v2.6.5) (2022-05-03) +[All Commits](https://github.com/traefik/traefik/compare/v2.6.3...v2.6.5) + +Release canceled. + +## [v2.6.4](https://github.com/traefik/traefik/tree/v2.6.4) (2022-05-03) +[All Commits](https://github.com/traefik/traefik/compare/v2.6.3...v2.6.4) + +Release canceled. + ## [v2.7.0-rc2](https://github.com/traefik/traefik/tree/v2.7.0-rc2) (2022-03-29) [All Commits](https://github.com/traefik/traefik/compare/v2.7.0-rc1...v2.7.0-rc2) diff --git a/Makefile b/Makefile index 4f454017a..ebccf5d01 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ build-webui-image: clean-webui: rm -r webui/static mkdir -p webui/static - echo 'For more information show `webui/readme.md`' > webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md + printf 'For more information see `webui/readme.md`' > webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md ## Generate WebUI webui/static/index.html: diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go index 0fec4f061..50ce0666d 100644 --- a/pkg/collector/collector.go +++ b/pkg/collector/collector.go @@ -16,7 +16,7 @@ import ( "github.com/traefik/traefik/v2/pkg/version" ) -// collectorURL URL where the stats are send. +// collectorURL URL where the stats are sent. const collectorURL = "https://collect.traefik.io/9vxmmkcdmalbdi635d4jgc5p5rx0h7h8" // Collected data. @@ -30,16 +30,30 @@ type data struct { // Collect anonymous data. func Collect(staticConfiguration *static.Configuration) error { - anonConfig, err := redactor.Anonymize(staticConfiguration) + buf, err := createBody(staticConfiguration) if err != nil { return err } + resp, err := makeHTTPClient().Post(collectorURL, "application/json; charset=utf-8", buf) + if resp != nil { + _ = resp.Body.Close() + } + + return err +} + +func createBody(staticConfiguration *static.Configuration) (*bytes.Buffer, error) { + anonConfig, err := redactor.Anonymize(staticConfiguration) + if err != nil { + return nil, err + } + log.WithoutContext().Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig) hashConf, err := hashstructure.Hash(staticConfiguration, nil) if err != nil { - return err + return nil, err } data := &data{ @@ -53,15 +67,10 @@ func Collect(staticConfiguration *static.Configuration) error { buf := new(bytes.Buffer) err = json.NewEncoder(buf).Encode(data) if err != nil { - return err + return nil, err } - resp, err := makeHTTPClient().Post(collectorURL, "application/json; charset=utf-8", buf) - if resp != nil { - resp.Body.Close() - } - - return err + return buf, err } func makeHTTPClient() *http.Client { diff --git a/pkg/collector/collector_test.go b/pkg/collector/collector_test.go new file mode 100644 index 000000000..b091f0c4f --- /dev/null +++ b/pkg/collector/collector_test.go @@ -0,0 +1,21 @@ +package collector + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/traefik/traefik/v2/pkg/config/static" +) + +func Test_createBody(t *testing.T) { + var staticConfiguration static.Configuration + + err := hydrate(&staticConfiguration) + require.NoError(t, err) + + buffer, err := createBody(&staticConfiguration) + require.NoError(t, err) + + assert.NotEmpty(t, buffer) +} diff --git a/pkg/collector/hydration_test.go b/pkg/collector/hydration_test.go new file mode 100644 index 000000000..8814888a6 --- /dev/null +++ b/pkg/collector/hydration_test.go @@ -0,0 +1,166 @@ +package collector + +import ( + "fmt" + "reflect" + "time" + + "github.com/traefik/paerser/types" +) + +const ( + sliceItemNumber = 2 + mapItemNumber = 2 + defaultString = "foobar" + defaultNumber = 42 + defaultBool = true + defaultMapKeyPrefix = "name" +) + +func hydrate(element interface{}) error { + field := reflect.ValueOf(element) + return fill(field) +} + +func fill(field reflect.Value) error { + switch field.Kind() { + case reflect.Struct: + if err := setStruct(field); err != nil { + return err + } + case reflect.Ptr: + if err := setPointer(field); err != nil { + return err + } + case reflect.Slice: + if err := setSlice(field); err != nil { + return err + } + case reflect.Map: + if err := setMap(field); err != nil { + return err + } + case reflect.Interface: + if err := fill(field.Elem()); err != nil { + return err + } + case reflect.String: + setTyped(field, defaultString) + case reflect.Int: + setTyped(field, defaultNumber) + case reflect.Int8: + setTyped(field, int8(defaultNumber)) + case reflect.Int16: + setTyped(field, int16(defaultNumber)) + case reflect.Int32: + setTyped(field, int32(defaultNumber)) + case reflect.Int64: + switch field.Type() { + case reflect.TypeOf(types.Duration(time.Second)): + setTyped(field, int64(defaultNumber*int(time.Second))) + default: + setTyped(field, int64(defaultNumber)) + } + case reflect.Uint: + setTyped(field, uint(defaultNumber)) + case reflect.Uint8: + setTyped(field, uint8(defaultNumber)) + case reflect.Uint16: + setTyped(field, uint16(defaultNumber)) + case reflect.Uint32: + setTyped(field, uint32(defaultNumber)) + case reflect.Uint64: + setTyped(field, uint64(defaultNumber)) + case reflect.Bool: + setTyped(field, defaultBool) + case reflect.Float32: + setTyped(field, float32(defaultNumber)) + case reflect.Float64: + setTyped(field, float64(defaultNumber)) + } + + return nil +} + +func setTyped(field reflect.Value, i interface{}) { + baseValue := reflect.ValueOf(i) + if field.Kind().String() == field.Type().String() { + field.Set(baseValue) + } else { + field.Set(baseValue.Convert(field.Type())) + } +} + +func setMap(field reflect.Value) error { + field.Set(reflect.MakeMap(field.Type())) + + for i := 0; i < mapItemNumber; i++ { + baseKeyName := makeKeyName(field.Type().Elem()) + key := reflect.ValueOf(fmt.Sprintf("%s%d", baseKeyName, i)) + + // generate value + ptrType := reflect.PtrTo(field.Type().Elem()) + ptrValue := reflect.New(ptrType) + if err := fill(ptrValue); err != nil { + return err + } + value := ptrValue.Elem().Elem() + + field.SetMapIndex(key, value) + } + return nil +} + +func makeKeyName(typ reflect.Type) string { + switch typ.Kind() { + case reflect.Ptr: + return typ.Elem().Name() + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Bool, reflect.Float32, reflect.Float64: + return defaultMapKeyPrefix + default: + return typ.Name() + } +} + +func setStruct(field reflect.Value) error { + for i := 0; i < field.NumField(); i++ { + fld := field.Field(i) + stFld := field.Type().Field(i) + + if !stFld.IsExported() || fld.Kind() == reflect.Func { + continue + } + + if err := fill(fld); err != nil { + return err + } + } + return nil +} + +func setSlice(field reflect.Value) error { + field.Set(reflect.MakeSlice(field.Type(), sliceItemNumber, sliceItemNumber)) + for j := 0; j < field.Len(); j++ { + if err := fill(field.Index(j)); err != nil { + return err + } + } + return nil +} + +func setPointer(field reflect.Value) error { + if field.IsNil() { + field.Set(reflect.New(field.Type().Elem())) + if err := fill(field.Elem()); err != nil { + return err + } + } else { + if err := fill(field.Elem()); err != nil { + return err + } + } + return nil +} diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go index df02a5a32..a403b94ba 100644 --- a/pkg/provider/acme/provider.go +++ b/pkg/provider/acme/provider.go @@ -538,7 +538,7 @@ func (p *Provider) addCertificateForDomain(domain types.Domain, certificate, key // The second (RenewInterval) is the interval between renew attempts. func getCertificateRenewDurations(certificatesDuration int) (time.Duration, time.Duration) { switch { - case certificatesDuration >= 265*24: // >= 1 year + case certificatesDuration >= 365*24: // >= 1 year return 4 * 30 * 24 * time.Hour, 7 * 24 * time.Hour // 4 month, 1 week case certificatesDuration >= 3*30*24: // >= 90 days return 30 * 24 * time.Hour, 24 * time.Hour // 30 days, 1 day diff --git a/pkg/provider/acme/provider_test.go b/pkg/provider/acme/provider_test.go index 64bcf1085..103eff59e 100644 --- a/pkg/provider/acme/provider_test.go +++ b/pkg/provider/acme/provider_test.go @@ -608,11 +608,17 @@ func Test_getCertificateRenewDurations(t *testing.T) { expectRenewInterval: time.Minute, }, { - desc: "1 Year certificates: 2 months renew period, 1 week renew interval", + desc: "1 Year certificates: 4 months renew period, 1 week renew interval", certificatesDurations: 24 * 365, expectRenewPeriod: time.Hour * 24 * 30 * 4, expectRenewInterval: time.Hour * 24 * 7, }, + { + desc: "265 Days certificates: 30 days renew period, 1 day renew interval", + certificatesDurations: 24 * 265, + expectRenewPeriod: time.Hour * 24 * 30, + expectRenewInterval: time.Hour * 24, + }, { desc: "90 Days certificates: 30 days renew period, 1 day renew interval", certificatesDurations: 24 * 90, diff --git a/pkg/provider/ecs/ecs.go b/pkg/provider/ecs/ecs.go index 13dafd8d8..0cde14508 100644 --- a/pkg/provider/ecs/ecs.go +++ b/pkg/provider/ecs/ecs.go @@ -392,6 +392,13 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl for _, container := range resp.ContainerInstances { instanceIds[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn) + // Disallow Instance IDs of the form mi-* + // This prevents considering external instances in ECS Anywhere setups + // and getting InvalidInstanceID.Malformed error when calling the describe-instances endpoint. + if strings.HasPrefix(aws.StringValue(container.Ec2InstanceId), "mi-") { + continue + } + instanceArns = append(instanceArns, container.Ec2InstanceId) } } diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml index 7ce934ea3..ce70637f0 100644 --- a/script/gcg/traefik-bugfix.toml +++ b/script/gcg/traefik-bugfix.toml @@ -4,11 +4,11 @@ RepositoryName = "traefik" OutputType = "file" FileName = "traefik_changelog.md" -# example new bugfix v2.6.3 +# example new bugfix v2.6.6 CurrentRef = "v2.6" -PreviousRef = "v2.6.2" +PreviousRef = "v2.6.5" BaseBranch = "v2.6" -FutureCurrentRefName = "v2.6.3" +FutureCurrentRefName = "v2.6.6" ThresholdPreviousRef = 10 ThresholdCurrentRef = 10 diff --git a/webui/dev/scripts/transfer.js b/webui/dev/scripts/transfer.js index ed812efff..eaa02bceb 100644 --- a/webui/dev/scripts/transfer.js +++ b/webui/dev/scripts/transfer.js @@ -5,7 +5,7 @@ const folder = process.argv[2] async function execute () { try { await fs.emptyDir('./static') - await fs.outputFile('./static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md', 'For more information show `webui/readme.md`') + await fs.outputFile('./static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md', 'For more information see `webui/readme.md`') console.log('Deleted static folder contents!') await fs.copy(`./dist/${folder}`, './static', { overwrite: true }) console.log('Installed new files in static folder!') diff --git a/webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md b/webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md index 03873182c..9481a99c3 100644 --- a/webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md +++ b/webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md @@ -1 +1 @@ -For more information show `webui/readme.md` +For more information see `webui/readme.md` \ No newline at end of file