feat(aws-compat): queue attributes for Terraform (FifoQueue, ContentBasedDeduplication, Policy, real timestamps)
- GetQueueAttributes now returns FifoQueue, ContentBasedDeduplication, Policy and real Created/LastModifiedTimestamp (previously missing/stubbed '0000000000') - Queue: add CreatedAt, LastModifiedAt, Policy, ContentBasedDeduplication - parse FifoQueue/ContentBasedDeduplication in both protocols (StringToBool) - Policy/RedriveAllowPolicy: normalize JSON-string form to object (JSON protocol sent them as string -> SetQueueAttributes failed with InvalidParameterValue) - persistence: keep new fields in meta DTO + backfill empty timestamps on load - FIFO dedup is inherent: IsDuplicate/InitDuplicatation gate on IsFIFO only (env flag EnableDuplicates=false disabled dedup for all FIFO queues)
This commit is contained in:
@@ -59,6 +59,9 @@ func CreateQueueV1(req *http.Request) (int, interfaces.AbstractResponseBody) {
|
||||
IsFIFO: utils.HasFIFOQueueName(queueName),
|
||||
EnableDuplicates: models.CurrentEnvironment.EnableDuplicates,
|
||||
Duplicates: make(map[string]time.Time),
|
||||
// CreatedTimestamp/LastModifiedTimestamp в GetQueueAttributes (AWS их отдаёт).
|
||||
CreatedAt: time.Now().UTC(),
|
||||
LastModifiedAt: time.Now().UTC(),
|
||||
}
|
||||
// Список имён переданных атрибутов — для whitelist-валидации
|
||||
// (Query-протокол: Attribute.N.Name; JSON: nil — проверка пропускается).
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"shared-sqs/app/interfaces"
|
||||
"shared-sqs/app/models"
|
||||
@@ -86,6 +87,13 @@ func GetQueueAttributesV1(req *http.Request) (int, interfaces.AbstractResponseBo
|
||||
if shouldInclude("VisibilityTimeout") {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "VisibilityTimeout", Value: strconv.Itoa(queue.VisibilityTimeout)})
|
||||
}
|
||||
// FIFO-атрибуты: читаются Terraform (aws_sqs_queue) и aws cli; без них — drift.
|
||||
if shouldInclude("FifoQueue") {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "FifoQueue", Value: strconv.FormatBool(queue.IsFIFO)})
|
||||
}
|
||||
if shouldInclude("ContentBasedDeduplication") {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "ContentBasedDeduplication", Value: strconv.FormatBool(queue.ContentBasedDeduplication)})
|
||||
}
|
||||
if shouldInclude("ApproximateNumberOfMessages") {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "ApproximateNumberOfMessages", Value: strconv.Itoa(queue.LiveCount())})
|
||||
}
|
||||
@@ -93,10 +101,10 @@ func GetQueueAttributesV1(req *http.Request) (int, interfaces.AbstractResponseBo
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "ApproximateNumberOfMessagesNotVisible", Value: strconv.Itoa(numberOfHiddenMessagesInQueue(queue))})
|
||||
}
|
||||
if shouldInclude("CreatedTimestamp") {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "CreatedTimestamp", Value: "0000000000"})
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "CreatedTimestamp", Value: epochSeconds(queue.CreatedAt)})
|
||||
}
|
||||
if shouldInclude("LastModifiedTimestamp") {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "LastModifiedTimestamp", Value: "0000000000"})
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "LastModifiedTimestamp", Value: epochSeconds(queue.LastModifiedAt)})
|
||||
}
|
||||
if shouldInclude("QueueArn") {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "QueueArn", Value: queue.Arn})
|
||||
@@ -107,6 +115,10 @@ func GetQueueAttributesV1(req *http.Request) (int, interfaces.AbstractResponseBo
|
||||
Value: fmt.Sprintf(`{"maxReceiveCount":"%d", "deadLetterTargetArn":"%s"}`, queue.MaxReceiveCount, queue.DeadLetterQueue.Arn),
|
||||
})
|
||||
}
|
||||
// Policy — отдаём сохранённую JSON-строку как есть (совместимость с Terraform).
|
||||
if shouldInclude("Policy") && queue.Policy != "" {
|
||||
queueAttributes = append(queueAttributes, models.Attribute{Name: "Policy", Value: queue.Policy})
|
||||
}
|
||||
|
||||
respStruct := models.GetQueueAttributesResponse{
|
||||
Xmlns: models.BaseXmlns,
|
||||
@@ -115,3 +127,12 @@ func GetQueueAttributesV1(req *http.Request) (int, interfaces.AbstractResponseBo
|
||||
}
|
||||
return http.StatusOK, respStruct
|
||||
}
|
||||
|
||||
// epochSeconds — timestamp в формате AWS (unix-секунды строкой).
|
||||
// Нулевое время отдаём как "0" (стабильно, без drift при чтении).
|
||||
func epochSeconds(t time.Time) string {
|
||||
if t.IsZero() {
|
||||
return "0"
|
||||
}
|
||||
return strconv.FormatInt(t.Unix(), 10)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package gosqs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@@ -85,5 +87,24 @@ func setQueueAttributesV1(q *models.Queue, attr models.QueueAttributes, provided
|
||||
q.DeadLetterQueue = deadLetterQueue
|
||||
q.MaxReceiveCount = attr.RedrivePolicy.MaxReceiveCount.Int()
|
||||
}
|
||||
|
||||
// Шаг 4: FIFO-атрибуты и Policy — храним как есть (совместимость с Terraform).
|
||||
// FifoQueue только включаем (выключить FIFO у существующей очереди нельзя —
|
||||
// как и в AWS). ContentBasedDeduplication и Policy не исполняются,
|
||||
// но должны возвращаться в GetQueueAttributes, иначе drift в Terraform.
|
||||
if attr.FifoQueue.Bool() {
|
||||
q.IsFIFO = true
|
||||
}
|
||||
if attr.ContentBasedDeduplication.Bool() {
|
||||
q.ContentBasedDeduplication = true
|
||||
}
|
||||
if attr.Policy != nil {
|
||||
// Сохраняем канонический JSON (map → marshal сортирует ключи) —
|
||||
// детерминированно, без drift при чтении.
|
||||
if data, err := json.Marshal(attr.Policy); err == nil {
|
||||
q.Policy = string(data)
|
||||
}
|
||||
}
|
||||
q.LastModifiedAt = time.Now().UTC()
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user