go.temporal.io/server@v1.23.0/common/archiver/archival_metadata.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  //go:generate mockgen -copyright_file ../../LICENSE -package $GOPACKAGE -source $GOFILE -destination archival_metadata_mock.go
    26  
    27  package archiver
    28  
    29  import (
    30  	"fmt"
    31  	"strings"
    32  
    33  	enumspb "go.temporal.io/api/enums/v1"
    34  
    35  	"go.temporal.io/server/common/config"
    36  
    37  	"go.temporal.io/server/common/dynamicconfig"
    38  )
    39  
    40  type (
    41  	// ArchivalMetadata provides cluster level archival information
    42  	ArchivalMetadata interface {
    43  		GetHistoryConfig() ArchivalConfig
    44  		GetVisibilityConfig() ArchivalConfig
    45  	}
    46  
    47  	// ArchivalConfig is an immutable representation of the archival configuration of the cluster
    48  	// This config is determined at cluster startup time
    49  	ArchivalConfig interface {
    50  		ClusterConfiguredForArchival() bool
    51  		GetClusterState() ArchivalState
    52  		ReadEnabled() bool
    53  		GetNamespaceDefaultState() enumspb.ArchivalState
    54  		GetNamespaceDefaultURI() string
    55  		StaticClusterState() ArchivalState
    56  	}
    57  
    58  	archivalMetadata struct {
    59  		historyConfig    ArchivalConfig
    60  		visibilityConfig ArchivalConfig
    61  	}
    62  
    63  	archivalConfig struct {
    64  		staticClusterState    ArchivalState
    65  		dynamicClusterState   dynamicconfig.StringPropertyFn
    66  		enableRead            dynamicconfig.BoolPropertyFn
    67  		namespaceDefaultState enumspb.ArchivalState
    68  		namespaceDefaultURI   string
    69  	}
    70  
    71  	// ArchivalState represents the archival state of the cluster
    72  	ArchivalState int
    73  )
    74  
    75  func (a *archivalConfig) StaticClusterState() ArchivalState {
    76  	return a.staticClusterState
    77  }
    78  
    79  const (
    80  	// ArchivalDisabled means this cluster is not configured to handle archival
    81  	ArchivalDisabled ArchivalState = iota
    82  	// ArchivalPaused means this cluster is configured to handle archival but is currently not archiving
    83  	// This state is not yet implemented, as of now ArchivalPaused is treated the same way as ArchivalDisabled
    84  	ArchivalPaused
    85  	// ArchivalEnabled means this cluster is currently archiving
    86  	ArchivalEnabled
    87  )
    88  
    89  // NewArchivalMetadata constructs a new ArchivalMetadata
    90  func NewArchivalMetadata(
    91  	dc *dynamicconfig.Collection,
    92  	historyState string,
    93  	historyReadEnabled bool,
    94  	visibilityState string,
    95  	visibilityReadEnabled bool,
    96  	namespaceDefaults *config.ArchivalNamespaceDefaults,
    97  ) ArchivalMetadata {
    98  	historyConfig := NewArchivalConfig(
    99  		historyState,
   100  		dc.GetStringProperty(dynamicconfig.HistoryArchivalState, historyState),
   101  		dc.GetBoolProperty(dynamicconfig.EnableReadFromHistoryArchival, historyReadEnabled),
   102  		namespaceDefaults.History.State,
   103  		namespaceDefaults.History.URI,
   104  	)
   105  
   106  	visibilityConfig := NewArchivalConfig(
   107  		visibilityState,
   108  		dc.GetStringProperty(dynamicconfig.VisibilityArchivalState, visibilityState),
   109  		dc.GetBoolProperty(dynamicconfig.EnableReadFromVisibilityArchival, visibilityReadEnabled),
   110  		namespaceDefaults.Visibility.State,
   111  		namespaceDefaults.Visibility.URI,
   112  	)
   113  
   114  	return &archivalMetadata{
   115  		historyConfig:    historyConfig,
   116  		visibilityConfig: visibilityConfig,
   117  	}
   118  }
   119  
   120  func (metadata *archivalMetadata) GetHistoryConfig() ArchivalConfig {
   121  	return metadata.historyConfig
   122  }
   123  
   124  func (metadata *archivalMetadata) GetVisibilityConfig() ArchivalConfig {
   125  	return metadata.visibilityConfig
   126  }
   127  
   128  // NewArchivalConfig constructs a new valid ArchivalConfig
   129  func NewArchivalConfig(
   130  	staticClusterStateStr string,
   131  	dynamicClusterState dynamicconfig.StringPropertyFn,
   132  	enableRead dynamicconfig.BoolPropertyFn,
   133  	namespaceDefaultStateStr string,
   134  	namespaceDefaultURI string,
   135  ) ArchivalConfig {
   136  	staticClusterState, err := getClusterArchivalState(staticClusterStateStr)
   137  	if err != nil {
   138  		panic(err)
   139  	}
   140  	namespaceDefaultState, err := getNamespaceArchivalState(namespaceDefaultStateStr)
   141  	if err != nil {
   142  		panic(err)
   143  	}
   144  
   145  	return &archivalConfig{
   146  		staticClusterState:    staticClusterState,
   147  		dynamicClusterState:   dynamicClusterState,
   148  		enableRead:            enableRead,
   149  		namespaceDefaultState: namespaceDefaultState,
   150  		namespaceDefaultURI:   namespaceDefaultURI,
   151  	}
   152  }
   153  
   154  // NewDisabledArchvialConfig returns an ArchivalConfig where archival is disabled for both the cluster and the namespace
   155  func NewDisabledArchvialConfig() ArchivalConfig {
   156  	return &archivalConfig{
   157  		staticClusterState:    ArchivalDisabled,
   158  		dynamicClusterState:   nil,
   159  		enableRead:            nil,
   160  		namespaceDefaultState: enumspb.ARCHIVAL_STATE_DISABLED,
   161  		namespaceDefaultURI:   "",
   162  	}
   163  }
   164  
   165  // NewEnabledArchivalConfig returns an ArchivalConfig where archival is enabled for both the cluster and the namespace
   166  func NewEnabledArchivalConfig() ArchivalConfig {
   167  	return &archivalConfig{
   168  		staticClusterState:    ArchivalEnabled,
   169  		dynamicClusterState:   dynamicconfig.GetStringPropertyFn("enabled"),
   170  		enableRead:            dynamicconfig.GetBoolPropertyFn(true),
   171  		namespaceDefaultState: enumspb.ARCHIVAL_STATE_ENABLED,
   172  		namespaceDefaultURI:   "some-uri",
   173  	}
   174  }
   175  
   176  // ClusterConfiguredForArchival returns true if cluster is configured to handle archival, false otherwise
   177  func (a *archivalConfig) ClusterConfiguredForArchival() bool {
   178  	return a.GetClusterState() == ArchivalEnabled
   179  }
   180  
   181  func (a *archivalConfig) GetClusterState() ArchivalState {
   182  	// Only check dynamic config when archival is enabled in static config.
   183  	// If archival is disabled in static config, there will be no provider section in the static config
   184  	// and the archiver provider can not create any archiver. Therefore, in that case,
   185  	// even dynamic config says archival is enabled, we should ignore that.
   186  	// Only when archival is enabled in static config, should we check if there's any difference between static config and dynamic config.
   187  	if a.staticClusterState != ArchivalEnabled {
   188  		return a.staticClusterState
   189  	}
   190  
   191  	dynamicStateStr := a.dynamicClusterState()
   192  	dynamicState, err := getClusterArchivalState(dynamicStateStr)
   193  	if err != nil {
   194  		return ArchivalDisabled
   195  	}
   196  	return dynamicState
   197  }
   198  
   199  func (a *archivalConfig) ReadEnabled() bool {
   200  	if !a.ClusterConfiguredForArchival() {
   201  		return false
   202  	}
   203  	return a.enableRead()
   204  }
   205  
   206  func (a *archivalConfig) GetNamespaceDefaultState() enumspb.ArchivalState {
   207  	return a.namespaceDefaultState
   208  }
   209  
   210  func (a *archivalConfig) GetNamespaceDefaultURI() string {
   211  	return a.namespaceDefaultURI
   212  }
   213  
   214  func getClusterArchivalState(str string) (ArchivalState, error) {
   215  	str = strings.TrimSpace(strings.ToLower(str))
   216  	switch str {
   217  	case "", config.ArchivalDisabled:
   218  		return ArchivalDisabled, nil
   219  	case config.ArchivalPaused:
   220  		return ArchivalPaused, nil
   221  	case config.ArchivalEnabled:
   222  		return ArchivalEnabled, nil
   223  	}
   224  	return ArchivalDisabled, fmt.Errorf("invalid archival state of %v for cluster, valid states are: {\"\", \"disabled\", \"paused\", \"enabled\"}", str)
   225  }
   226  
   227  func getNamespaceArchivalState(str string) (enumspb.ArchivalState, error) {
   228  	str = strings.TrimSpace(strings.ToLower(str))
   229  	switch str {
   230  	case "", config.ArchivalDisabled:
   231  		return enumspb.ARCHIVAL_STATE_DISABLED, nil
   232  	case config.ArchivalEnabled:
   233  		return enumspb.ARCHIVAL_STATE_ENABLED, nil
   234  	}
   235  	return enumspb.ARCHIVAL_STATE_DISABLED, fmt.Errorf("invalid archival state of %v for namespace, valid states are: {\"\", \"disabled\", \"enabled\"}", str)
   236  }