mirror of
https://github.com/status-im/consul.git
synced 2025-01-09 05:23:04 +00:00
5fb9df1640
* Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at <Blog URL>, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
182 lines
5.3 KiB
Go
182 lines
5.3 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package configentry
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/consul/agent/cache"
|
|
"github.com/hashicorp/consul/agent/rpcclient"
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
"github.com/hashicorp/consul/agent/submatview"
|
|
"github.com/hashicorp/consul/proto/private/pbsubscribe"
|
|
)
|
|
|
|
// Client provides access to config entry data.
|
|
type Client struct {
|
|
rpcclient.Client
|
|
}
|
|
|
|
// GetSamenessGroup returns the sameness group config entry (if possible) given the
|
|
// provided config entry query
|
|
func (c *Client) GetSamenessGroup(
|
|
ctx context.Context,
|
|
req *structs.ConfigEntryQuery,
|
|
) (structs.SamenessGroupConfigEntry, cache.ResultMeta, error) {
|
|
if req.Kind != structs.SamenessGroup {
|
|
return structs.SamenessGroupConfigEntry{}, cache.ResultMeta{}, fmt.Errorf("wrong kind in query %s, expected %s", req.Kind, structs.SamenessGroup)
|
|
}
|
|
|
|
out, meta, err := c.GetConfigEntry(ctx, req)
|
|
if err != nil {
|
|
return structs.SamenessGroupConfigEntry{}, cache.ResultMeta{}, err
|
|
}
|
|
|
|
sg, ok := out.Entry.(*structs.SamenessGroupConfigEntry)
|
|
if !ok {
|
|
return structs.SamenessGroupConfigEntry{}, cache.ResultMeta{}, fmt.Errorf("%s config entry with name %s not found", structs.SamenessGroup, req.Name)
|
|
}
|
|
return *sg, meta, nil
|
|
}
|
|
|
|
// GetConfigEntry returns the config entry (if possible) given the
|
|
// provided config entry query
|
|
func (c *Client) GetConfigEntry(
|
|
ctx context.Context,
|
|
req *structs.ConfigEntryQuery,
|
|
) (structs.ConfigEntryResponse, cache.ResultMeta, error) {
|
|
if c.UseStreamingBackend && (req.QueryOptions.UseCache || req.QueryOptions.MinQueryIndex > 0) {
|
|
c.QueryOptionDefaults(&req.QueryOptions)
|
|
cfgReq, err := c.newConfigEntryRequest(req)
|
|
if err != nil {
|
|
return structs.ConfigEntryResponse{}, cache.ResultMeta{}, err
|
|
}
|
|
result, err := c.ViewStore.Get(ctx, cfgReq)
|
|
if err != nil {
|
|
return structs.ConfigEntryResponse{}, cache.ResultMeta{}, err
|
|
}
|
|
meta := cache.ResultMeta{Index: result.Index, Hit: result.Cached}
|
|
return *result.Value.(*structs.ConfigEntryResponse), meta, err
|
|
}
|
|
|
|
out, md, err := c.getConfigEntryRPC(ctx, req)
|
|
if err != nil {
|
|
return out, md, err
|
|
}
|
|
|
|
if req.QueryOptions.AllowStale && req.QueryOptions.MaxStaleDuration > 0 && out.LastContact > req.MaxStaleDuration {
|
|
req.AllowStale = false
|
|
err := c.NetRPC.RPC(ctx, "ConfigEntry.Get", &req, &out)
|
|
return out, cache.ResultMeta{}, err
|
|
}
|
|
|
|
return out, md, err
|
|
}
|
|
|
|
func (c *Client) getConfigEntryRPC(
|
|
ctx context.Context,
|
|
req *structs.ConfigEntryQuery,
|
|
) (structs.ConfigEntryResponse, cache.ResultMeta, error) {
|
|
var out structs.ConfigEntryResponse
|
|
if !req.QueryOptions.UseCache {
|
|
err := c.NetRPC.RPC(context.Background(), "ConfigEntry.Get", req, &out)
|
|
return out, cache.ResultMeta{}, err
|
|
}
|
|
|
|
raw, md, err := c.Cache.Get(ctx, c.CacheName, req)
|
|
if err != nil {
|
|
return out, md, err
|
|
}
|
|
|
|
value, ok := raw.(*structs.ConfigEntryResponse)
|
|
if !ok {
|
|
panic("wrong response type for cachetype.HealthServicesName")
|
|
}
|
|
|
|
return *value, md, nil
|
|
}
|
|
|
|
var _ submatview.Request = (*configEntryRequest)(nil)
|
|
|
|
type configEntryRequest struct {
|
|
Topic pbsubscribe.Topic
|
|
req *structs.ConfigEntryQuery
|
|
deps rpcclient.MaterializerDeps
|
|
}
|
|
|
|
func (c *Client) newConfigEntryRequest(req *structs.ConfigEntryQuery) (*configEntryRequest, error) {
|
|
var topic pbsubscribe.Topic
|
|
switch req.Kind {
|
|
case structs.SamenessGroup:
|
|
topic = pbsubscribe.Topic_SamenessGroup
|
|
default:
|
|
return nil, fmt.Errorf("cannot map config entry kind: %q to a topic", req.Kind)
|
|
}
|
|
return &configEntryRequest{
|
|
Topic: topic,
|
|
req: req,
|
|
deps: c.MaterializerDeps,
|
|
}, nil
|
|
}
|
|
|
|
// CacheInfo returns information used for caching the config entry request.
|
|
func (r *configEntryRequest) CacheInfo() cache.RequestInfo {
|
|
return r.req.CacheInfo()
|
|
}
|
|
|
|
// Type returns a string which uniquely identifies the config entry of request.
|
|
// The returned value is used as the prefix of the key used to index
|
|
// entries in the Store.
|
|
func (r *configEntryRequest) Type() string {
|
|
return "agent.rpcclient.configentry.configentryrequest"
|
|
}
|
|
|
|
// Request creates a new pbsubscribe.SubscribeRequest for a config entry including
|
|
// wildcards and enterprise fields
|
|
func (r *configEntryRequest) Request(index uint64) *pbsubscribe.SubscribeRequest {
|
|
req := &pbsubscribe.SubscribeRequest{
|
|
Topic: r.Topic,
|
|
Index: index,
|
|
Datacenter: r.req.Datacenter,
|
|
Token: r.req.QueryOptions.Token,
|
|
}
|
|
|
|
if name := r.req.Name; name == "" {
|
|
req.Subject = &pbsubscribe.SubscribeRequest_WildcardSubject{
|
|
WildcardSubject: true,
|
|
}
|
|
} else {
|
|
req.Subject = &pbsubscribe.SubscribeRequest_NamedSubject{
|
|
NamedSubject: &pbsubscribe.NamedSubject{
|
|
Key: name,
|
|
Partition: r.req.PartitionOrDefault(),
|
|
Namespace: r.req.NamespaceOrDefault(),
|
|
},
|
|
}
|
|
}
|
|
|
|
return req
|
|
}
|
|
|
|
// NewMaterializer will be called if there is no active materializer to fulfill
|
|
// the request. It returns a Materializer appropriate for streaming
|
|
// data to fulfil the config entry request.
|
|
func (r *configEntryRequest) NewMaterializer() (submatview.Materializer, error) {
|
|
var view submatview.View
|
|
if r.req.Name == "" {
|
|
view = NewConfigEntryListView(r.req.Kind, r.req.EnterpriseMeta)
|
|
} else {
|
|
view = &ConfigEntryView{}
|
|
}
|
|
|
|
deps := submatview.Deps{
|
|
View: view,
|
|
Logger: r.deps.Logger,
|
|
Request: r.Request,
|
|
}
|
|
|
|
return submatview.NewRPCMaterializer(pbsubscribe.NewStateChangeSubscriptionClient(r.deps.Conn), deps), nil
|
|
}
|