diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c7651e0e..b072b7ed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Changelog for Cass Operator, new PRs should update the `main / unreleased` secti * [CHANGE] #202 Support fetching FeatureSet from management-api if available. Return RequestError with StatusCode when endpoint has bad status. * [ENHANCEMENT] #175 Add FQL reconciliation via parseFQLFromConfig and SetFullQueryLogging called from ReconcileAllRacks. CallIsFullQueryLogEnabledEndpoint and CallSetFullQueryLog functions to httphelper. * [ENHANCEMENT] #185 Add more app.kubernetes.io labels to all the managed resources +* [ENHANCEMENT] Validate dc.Spec.Config properties against the Cassandra's allowed config value list ## v1.8.0 * [CHANGE] #178 If clusterName includes characters not allowed in the serviceName, strip those chars from service name. diff --git a/Makefile b/Makefile index 1f4c8dbb7..5e01e07fc 100644 --- a/Makefile +++ b/Makefile @@ -86,6 +86,9 @@ manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and Cust generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." +generate-configs: + cd hack/config && ./generate.sh + fmt: ## Run go fmt against code. go fmt ./... @@ -96,7 +99,7 @@ test: manifests generate fmt vet envtest ## Run tests. # Old unit tests first - these use mocked client / fakeclient go test ./pkg/... -coverprofile cover-operator.out # Then the envtest ones - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./controllers/... -coverprofile cover.out + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./apis/... ./controllers/... -coverprofile cover.out integ-test: kustomize cert-manager ## Run integration tests from directory M_INTEG_DIR or set M_INTEG_DIR=all to run all the integration tests. ifeq ($(M_INTEG_DIR), all) diff --git a/apis/cassandra/v1beta1/cassandra_config_generated.go b/apis/cassandra/v1beta1/cassandra_config_generated.go new file mode 100644 index 000000000..d84a3b45e --- /dev/null +++ b/apis/cassandra/v1beta1/cassandra_config_generated.go @@ -0,0 +1,725 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code is generated with hack/config. DO NOT EDIT. +package v1beta1 + +import ( + "strconv" + "strings" +) + +type CassandraConfigValues struct { + accepted map[string]interface{} +} + +func (c *CassandraConfigValues) HasProperty(propertyName string) bool { + _, found := c.accepted[propertyName] + return found +} + +func GetCassandraConfigValues(serverVersion string) (*CassandraConfigValues, error) { + versionParts := strings.Split(serverVersion, ".") + serverMajorVersion, err := strconv.ParseInt(versionParts[0], 10, 8) + if err != nil { + return nil, err + } + + if serverMajorVersion == 3 { + // Return configuration for 3.11, regardless of the real version (we don't support <3.11) + return &config311, nil + } + + if serverMajorVersion == 4 { + serverMinorVersion, err := strconv.ParseInt(versionParts[1], 10, 8) + if err != nil { + return nil, err + } + if serverMinorVersion == 0 { + // Return config40 + return &config40, nil + } + } + // Something brand new.. + return &configtrunk, nil +} + +var ( + config311 = CassandraConfigValues{ + accepted: map[string]interface{}{ + "cluster_name": true, + "authenticator": true, + "authorizer": true, + "role_manager": true, + "permissions_validity_in_ms": true, + "permissions_cache_max_entries": true, + "permissions_update_interval_in_ms": true, + "roles_validity_in_ms": true, + "roles_cache_max_entries": true, + "roles_update_interval_in_ms": true, + "credentials_validity_in_ms": true, + "credentials_cache_max_entries": true, + "credentials_update_interval_in_ms": true, + "partitioner": true, + "auto_bootstrap": true, + "hinted_handoff_enabled": true, + "hinted_handoff_disabled_datacenters": true, + "max_hint_window_in_ms": true, + "hints_directory": true, + "seed_provider": true, + "disk_access_mode": true, + "disk_failure_policy": true, + "commit_failure_policy": true, + "initial_token": true, + "num_tokens": true, + "allocate_tokens_for_keyspace": true, + "request_timeout_in_ms": true, + "read_request_timeout_in_ms": true, + "range_request_timeout_in_ms": true, + "write_request_timeout_in_ms": true, + "counter_write_request_timeout_in_ms": true, + "cas_contention_timeout_in_ms": true, + "truncate_request_timeout_in_ms": true, + "streaming_socket_timeout_in_ms": true, + "streaming_keep_alive_period_in_secs": true, + "cross_node_timeout": true, + "slow_query_log_timeout_in_ms": true, + "phi_convict_threshold": true, + "concurrent_reads": true, + "concurrent_writes": true, + "concurrent_counter_writes": true, + "concurrent_materialized_view_writes": true, + "concurrent_replicates": true, + "memtable_flush_writers": true, + "memtable_heap_space_in_mb": true, + "memtable_offheap_space_in_mb": true, + "memtable_cleanup_threshold": true, + "repair_session_max_tree_depth": true, + "storage_port": true, + "ssl_storage_port": true, + "listen_address": true, + "listen_interface": true, + "listen_interface_prefer_ipv6": true, + "broadcast_address": true, + "listen_on_broadcast_address": true, + "internode_authenticator": true, + "start_rpc": true, + "rpc_address": true, + "rpc_interface": true, + "rpc_interface_prefer_ipv6": true, + "broadcast_rpc_address": true, + "rpc_port": true, + "rpc_listen_backlog": true, + "rpc_server_type": true, + "rpc_keepalive": true, + "rpc_min_threads": true, + "rpc_max_threads": true, + "rpc_send_buff_size_in_bytes": true, + "rpc_recv_buff_size_in_bytes": true, + "internode_send_buff_size_in_bytes": true, + "internode_recv_buff_size_in_bytes": true, + "start_native_transport": true, + "native_transport_port": true, + "native_transport_port_ssl": true, + "native_transport_max_threads": true, + "native_transport_max_frame_size_in_mb": true, + "native_transport_max_concurrent_connections": true, + "native_transport_max_concurrent_connections_per_ip": true, + "native_transport_flush_in_batches_legacy": true, + "native_transport_max_concurrent_requests_in_bytes_per_ip": true, + "native_transport_max_concurrent_requests_in_bytes": true, + "native_transport_max_negotiable_protocol_version": true, + "thrift_max_message_length_in_mb": true, + "max_value_size_in_mb": true, + "thrift_framed_transport_size_in_mb": true, + "snapshot_before_compaction": true, + "auto_snapshot": true, + "column_index_size_in_kb": true, + "column_index_cache_size_in_kb": true, + "batch_size_warn_threshold_in_kb": true, + "batch_size_fail_threshold_in_kb": true, + "unlogged_batch_across_partitions_warn_threshold": true, + "concurrent_compactors": true, + "compaction_throughput_mb_per_sec": true, + "compaction_large_partition_warning_threshold_mb": true, + "min_free_space_per_drive_in_mb": true, + "max_streaming_retries": true, + "stream_throughput_outbound_megabits_per_sec": true, + "inter_dc_stream_throughput_outbound_megabits_per_sec": true, + "data_file_directories": true, + "saved_caches_directory": true, + "commitlog_directory": true, + "commitlog_total_space_in_mb": true, + "commitlog_sync": true, + "commitlog_sync_batch_window_in_ms": true, + "commitlog_sync_period_in_ms": true, + "commitlog_segment_size_in_mb": true, + "commitlog_compression": true, + "commitlog_max_compression_buffers_in_pool": true, + "transparent_data_encryption_options": true, + "max_mutation_size_in_kb": true, + "cdc_enabled": true, + "cdc_raw_directory": true, + "cdc_total_space_in_mb": true, + "cdc_free_space_check_interval_ms": true, + "commitlog_periodic_queue_size": true, + "endpoint_snitch": true, + "dynamic_snitch": true, + "dynamic_snitch_update_interval_in_ms": true, + "dynamic_snitch_reset_interval_in_ms": true, + "dynamic_snitch_badness_threshold": true, + "request_scheduler": true, + "request_scheduler_id": true, + "request_scheduler_options": true, + "server_encryption_options": true, + "client_encryption_options": true, + "encryption_options": true, + "internode_compression": true, + "index_interval": true, + "hinted_handoff_throttle_in_kb": true, + "batchlog_replay_throttle_in_kb": true, + "max_hints_delivery_threads": true, + "hints_flush_period_in_ms": true, + "max_hints_file_size_in_mb": true, + "hints_compression": true, + "sstable_preemptive_open_interval_in_mb": true, + "incremental_backups": true, + "trickle_fsync": true, + "trickle_fsync_interval_in_kb": true, + "key_cache_size_in_mb": true, + "key_cache_save_period": true, + "key_cache_keys_to_save": true, + "row_cache_class_name": true, + "row_cache_size_in_mb": true, + "row_cache_save_period": true, + "row_cache_keys_to_save": true, + "counter_cache_size_in_mb": true, + "counter_cache_save_period": true, + "counter_cache_keys_to_save": true, + "file_cache_size_in_mb": true, + "file_cache_round_up": true, + "buffer_pool_use_heap_if_exhausted": true, + "disk_optimization_strategy": true, + "disk_optimization_estimate_percentile": true, + "disk_optimization_page_cross_chance": true, + "inter_dc_tcp_nodelay": true, + "memtable_allocation_type": true, + "tombstone_warn_threshold": true, + "tombstone_failure_threshold": true, + "replica_filtering_protection": true, + "index_summary_capacity_in_mb": true, + "index_summary_resize_interval_in_minutes": true, + "gc_log_threshold_in_ms": true, + "gc_warn_threshold_in_ms": true, + "tracetype_query_ttl": true, + "tracetype_repair_ttl": true, + "otc_coalescing_strategy": true, + "otc_coalescing_window_us": true, + "otc_coalescing_enough_coalesced_messages": true, + "otc_backlog_expiration_interval_ms": true, + "windows_timer_interval": true, + "prepared_statements_cache_size_mb": true, + "thrift_prepared_statements_cache_size_mb": true, + "enable_user_defined_functions": true, + "enable_scripted_user_defined_functions": true, + "enable_materialized_views": true, + "enable_sasi_indexes": true, + "enable_drop_compact_storage": true, + "enable_user_defined_functions_threads": true, + "user_defined_function_warn_timeout": true, + "user_defined_function_fail_timeout": true, + "user_function_timeout_policy": true, + "back_pressure_enabled": true, + "back_pressure_strategy": true, + "snapshot_on_duplicate_row_detection": true, + "check_for_duplicate_rows_during_reads": true, + "check_for_duplicate_rows_during_compaction": true, + }, + } + + config40 = CassandraConfigValues{ + accepted: map[string]interface{}{ + "cluster_name": true, + "authenticator": true, + "authorizer": true, + "role_manager": true, + "network_authorizer": true, + "permissions_validity_in_ms": true, + "permissions_cache_max_entries": true, + "permissions_update_interval_in_ms": true, + "roles_validity_in_ms": true, + "roles_cache_max_entries": true, + "roles_update_interval_in_ms": true, + "credentials_validity_in_ms": true, + "credentials_cache_max_entries": true, + "credentials_update_interval_in_ms": true, + "partitioner": true, + "auto_bootstrap": true, + "hinted_handoff_enabled": true, + "hinted_handoff_disabled_datacenters": true, + "max_hint_window_in_ms": true, + "hints_directory": true, + "seed_provider": true, + "disk_access_mode": true, + "disk_failure_policy": true, + "commit_failure_policy": true, + "initial_token": true, + "num_tokens": true, + "allocate_tokens_for_keyspace": true, + "allocate_tokens_for_local_replication_factor": true, + "native_transport_idle_timeout_in_ms": true, + "request_timeout_in_ms": true, + "read_request_timeout_in_ms": true, + "range_request_timeout_in_ms": true, + "write_request_timeout_in_ms": true, + "counter_write_request_timeout_in_ms": true, + "cas_contention_timeout_in_ms": true, + "truncate_request_timeout_in_ms": true, + "streaming_connections_per_host": true, + "streaming_keep_alive_period_in_secs": true, + "cross_node_timeout": true, + "slow_query_log_timeout_in_ms": true, + "phi_convict_threshold": true, + "concurrent_reads": true, + "concurrent_writes": true, + "concurrent_counter_writes": true, + "concurrent_materialized_view_writes": true, + "concurrent_replicates": true, + "memtable_flush_writers": true, + "memtable_heap_space_in_mb": true, + "memtable_offheap_space_in_mb": true, + "memtable_cleanup_threshold": true, + "repair_session_max_tree_depth": true, + "repair_session_space_in_mb": true, + "use_offheap_merkle_trees": true, + "storage_port": true, + "ssl_storage_port": true, + "listen_address": true, + "listen_interface": true, + "listen_interface_prefer_ipv6": true, + "broadcast_address": true, + "listen_on_broadcast_address": true, + "internode_authenticator": true, + "rpc_address": true, + "rpc_interface": true, + "rpc_interface_prefer_ipv6": true, + "broadcast_rpc_address": true, + "rpc_keepalive": true, + "internode_max_message_size_in_bytes": true, + "internode_socket_send_buffer_size_in_bytes": true, + "internode_socket_receive_buffer_size_in_bytes": true, + "internode_application_send_queue_capacity_in_bytes": true, + "internode_application_send_queue_reserve_endpoint_capacity_in_bytes": true, + "internode_application_send_queue_reserve_global_capacity_in_bytes": true, + "internode_application_receive_queue_capacity_in_bytes": true, + "internode_application_receive_queue_reserve_endpoint_capacity_in_bytes": true, + "internode_application_receive_queue_reserve_global_capacity_in_bytes": true, + "internode_tcp_connect_timeout_in_ms": true, + "internode_tcp_user_timeout_in_ms": true, + "internode_streaming_tcp_user_timeout_in_ms": true, + "start_native_transport": true, + "native_transport_port": true, + "native_transport_port_ssl": true, + "native_transport_max_threads": true, + "native_transport_max_frame_size_in_mb": true, + "native_transport_max_concurrent_connections": true, + "native_transport_max_concurrent_connections_per_ip": true, + "native_transport_flush_in_batches_legacy": true, + "native_transport_allow_older_protocols": true, + "native_transport_max_concurrent_requests_in_bytes_per_ip": true, + "native_transport_max_concurrent_requests_in_bytes": true, + "native_transport_receive_queue_capacity_in_bytes": true, + "native_transport_max_negotiable_protocol_version": true, + "max_value_size_in_mb": true, + "snapshot_before_compaction": true, + "auto_snapshot": true, + "snapshot_links_per_second": true, + "column_index_size_in_kb": true, + "column_index_cache_size_in_kb": true, + "batch_size_warn_threshold_in_kb": true, + "batch_size_fail_threshold_in_kb": true, + "unlogged_batch_across_partitions_warn_threshold": true, + "concurrent_compactors": true, + "compaction_throughput_mb_per_sec": true, + "compaction_large_partition_warning_threshold_mb": true, + "min_free_space_per_drive_in_mb": true, + "concurrent_materialized_view_builders": true, + "reject_repair_compaction_threshold": true, + "max_streaming_retries": true, + "stream_throughput_outbound_megabits_per_sec": true, + "inter_dc_stream_throughput_outbound_megabits_per_sec": true, + "data_file_directories": true, + "local_system_data_file_directory": true, + "saved_caches_directory": true, + "commitlog_directory": true, + "commitlog_total_space_in_mb": true, + "commitlog_sync": true, + "commitlog_sync_batch_window_in_ms": true, + "commitlog_sync_group_window_in_ms": true, + "commitlog_sync_period_in_ms": true, + "commitlog_segment_size_in_mb": true, + "commitlog_compression": true, + "flush_compression": true, + "commitlog_max_compression_buffers_in_pool": true, + "periodic_commitlog_sync_lag_block_in_ms": true, + "transparent_data_encryption_options": true, + "max_mutation_size_in_kb": true, + "cdc_enabled": true, + "cdc_raw_directory": true, + "cdc_total_space_in_mb": true, + "cdc_free_space_check_interval_ms": true, + "commitlog_periodic_queue_size": true, + "endpoint_snitch": true, + "dynamic_snitch": true, + "dynamic_snitch_update_interval_in_ms": true, + "dynamic_snitch_reset_interval_in_ms": true, + "dynamic_snitch_badness_threshold": true, + "server_encryption_options": true, + "client_encryption_options": true, + "internode_compression": true, + "hinted_handoff_throttle_in_kb": true, + "batchlog_replay_throttle_in_kb": true, + "max_hints_delivery_threads": true, + "hints_flush_period_in_ms": true, + "max_hints_file_size_in_mb": true, + "hints_compression": true, + "incremental_backups": true, + "trickle_fsync": true, + "trickle_fsync_interval_in_kb": true, + "sstable_preemptive_open_interval_in_mb": true, + "key_cache_migrate_during_compaction": true, + "key_cache_size_in_mb": true, + "key_cache_save_period": true, + "key_cache_keys_to_save": true, + "row_cache_class_name": true, + "row_cache_size_in_mb": true, + "row_cache_save_period": true, + "row_cache_keys_to_save": true, + "counter_cache_size_in_mb": true, + "counter_cache_save_period": true, + "counter_cache_keys_to_save": true, + "networking_cache_size_in_mb": true, + "file_cache_size_in_mb": true, + "file_cache_enabled": true, + "file_cache_round_up": true, + "buffer_pool_use_heap_if_exhausted": true, + "disk_optimization_strategy": true, + "disk_optimization_estimate_percentile": true, + "disk_optimization_page_cross_chance": true, + "inter_dc_tcp_nodelay": true, + "memtable_allocation_type": true, + "tombstone_warn_threshold": true, + "tombstone_failure_threshold": true, + "replica_filtering_protection": true, + "index_summary_capacity_in_mb": true, + "index_summary_resize_interval_in_minutes": true, + "gc_log_threshold_in_ms": true, + "gc_warn_threshold_in_ms": true, + "tracetype_query_ttl": true, + "tracetype_repair_ttl": true, + "ideal_consistency_level": true, + "otc_coalescing_strategy": true, + "otc_coalescing_window_us": true, + "otc_coalescing_enough_coalesced_messages": true, + "windows_timer_interval": true, + "prepared_statements_cache_size_mb": true, + "enable_user_defined_functions": true, + "enable_scripted_user_defined_functions": true, + "enable_materialized_views": true, + "enable_transient_replication": true, + "enable_sasi_indexes": true, + "enable_drop_compact_storage": true, + "enable_user_defined_functions_threads": true, + "user_defined_function_warn_timeout": true, + "user_defined_function_fail_timeout": true, + "user_function_timeout_policy": true, + "back_pressure_enabled": true, + "back_pressure_strategy": true, + "concurrent_validations": true, + "repair_command_pool_full_strategy": true, + "repair_command_pool_size": true, + "block_for_peers_timeout_in_secs": true, + "block_for_peers_in_remote_dcs": true, + "automatic_sstable_upgrade": true, + "max_concurrent_automatic_sstable_upgrades": true, + "stream_entire_sstables": true, + "audit_logging_options": true, + "full_query_logging_options": true, + "corrupted_tombstone_strategy": true, + "diagnostic_events_enabled": true, + "repaired_data_tracking_for_range_reads_enabled": true, + "repaired_data_tracking_for_partition_reads_enabled": true, + "report_unconfirmed_repaired_data_mismatches": true, + "snapshot_on_repaired_data_mismatch": true, + "validation_preview_purge_head_start_in_sec": true, + "initial_range_tombstone_list_allocation_size": true, + "range_tombstone_list_growth_factor": true, + "snapshot_on_duplicate_row_detection": true, + "check_for_duplicate_rows_during_reads": true, + "check_for_duplicate_rows_during_compaction": true, + "autocompaction_on_startup_enabled": true, + "auto_optimise_inc_repair_streams": true, + "auto_optimise_full_repair_streams": true, + "auto_optimise_preview_repair_streams": true, + "table_count_warn_threshold": true, + "keyspace_count_warn_threshold": true, + "consecutive_message_errors_threshold": true, + }, + } + + configtrunk = CassandraConfigValues{ + accepted: map[string]interface{}{ + "cluster_name": true, + "authenticator": true, + "authorizer": true, + "role_manager": true, + "network_authorizer": true, + "permissions_validity_in_ms": true, + "permissions_cache_max_entries": true, + "permissions_update_interval_in_ms": true, + "roles_validity_in_ms": true, + "roles_cache_max_entries": true, + "roles_update_interval_in_ms": true, + "credentials_validity_in_ms": true, + "credentials_cache_max_entries": true, + "credentials_update_interval_in_ms": true, + "partitioner": true, + "auto_bootstrap": true, + "hinted_handoff_enabled": true, + "hinted_handoff_disabled_datacenters": true, + "max_hint_window_in_ms": true, + "hints_directory": true, + "hint_window_persistent_enabled": true, + "seed_provider": true, + "disk_access_mode": true, + "disk_failure_policy": true, + "commit_failure_policy": true, + "use_deterministic_table_id": true, + "initial_token": true, + "num_tokens": true, + "allocate_tokens_for_keyspace": true, + "allocate_tokens_for_local_replication_factor": true, + "native_transport_idle_timeout_in_ms": true, + "request_timeout_in_ms": true, + "read_request_timeout_in_ms": true, + "range_request_timeout_in_ms": true, + "write_request_timeout_in_ms": true, + "counter_write_request_timeout_in_ms": true, + "cas_contention_timeout_in_ms": true, + "truncate_request_timeout_in_ms": true, + "streaming_connections_per_host": true, + "streaming_keep_alive_period_in_secs": true, + "cross_node_timeout": true, + "slow_query_log_timeout_in_ms": true, + "phi_convict_threshold": true, + "concurrent_reads": true, + "concurrent_writes": true, + "concurrent_counter_writes": true, + "concurrent_materialized_view_writes": true, + "available_processors": true, + "concurrent_replicates": true, + "memtable_flush_writers": true, + "memtable_heap_space_in_mb": true, + "memtable_offheap_space_in_mb": true, + "memtable_cleanup_threshold": true, + "repair_session_max_tree_depth": true, + "repair_session_space_in_mb": true, + "use_offheap_merkle_trees": true, + "storage_port": true, + "ssl_storage_port": true, + "listen_address": true, + "listen_interface": true, + "listen_interface_prefer_ipv6": true, + "broadcast_address": true, + "listen_on_broadcast_address": true, + "internode_authenticator": true, + "traverse_auth_from_root": true, + "rpc_address": true, + "rpc_interface": true, + "rpc_interface_prefer_ipv6": true, + "broadcast_rpc_address": true, + "rpc_keepalive": true, + "internode_max_message_size_in_bytes": true, + "internode_socket_send_buffer_size_in_bytes": true, + "internode_socket_receive_buffer_size_in_bytes": true, + "internode_application_send_queue_capacity_in_bytes": true, + "internode_application_send_queue_reserve_endpoint_capacity_in_bytes": true, + "internode_application_send_queue_reserve_global_capacity_in_bytes": true, + "internode_application_receive_queue_capacity_in_bytes": true, + "internode_application_receive_queue_reserve_endpoint_capacity_in_bytes": true, + "internode_application_receive_queue_reserve_global_capacity_in_bytes": true, + "internode_tcp_connect_timeout_in_ms": true, + "internode_tcp_user_timeout_in_ms": true, + "internode_streaming_tcp_user_timeout_in_ms": true, + "start_native_transport": true, + "native_transport_port": true, + "native_transport_port_ssl": true, + "native_transport_max_threads": true, + "native_transport_max_frame_size_in_mb": true, + "native_transport_max_concurrent_connections": true, + "native_transport_max_concurrent_connections_per_ip": true, + "native_transport_flush_in_batches_legacy": true, + "native_transport_allow_older_protocols": true, + "native_transport_max_concurrent_requests_in_bytes_per_ip": true, + "native_transport_max_concurrent_requests_in_bytes": true, + "native_transport_rate_limiting_enabled": true, + "native_transport_max_requests_per_second": true, + "native_transport_receive_queue_capacity_in_bytes": true, + "native_transport_max_negotiable_protocol_version": true, + "max_value_size_in_mb": true, + "snapshot_before_compaction": true, + "auto_snapshot": true, + "snapshot_links_per_second": true, + "column_index_size_in_kb": true, + "column_index_cache_size_in_kb": true, + "batch_size_warn_threshold_in_kb": true, + "batch_size_fail_threshold_in_kb": true, + "unlogged_batch_across_partitions_warn_threshold": true, + "concurrent_compactors": true, + "compaction_throughput_mb_per_sec": true, + "compaction_large_partition_warning_threshold_mb": true, + "min_free_space_per_drive_in_mb": true, + "compaction_tombstone_warning_threshold": true, + "concurrent_materialized_view_builders": true, + "reject_repair_compaction_threshold": true, + "max_streaming_retries": true, + "stream_throughput_outbound_megabits_per_sec": true, + "inter_dc_stream_throughput_outbound_megabits_per_sec": true, + "data_file_directories": true, + "local_system_data_file_directory": true, + "saved_caches_directory": true, + "commitlog_directory": true, + "commitlog_total_space_in_mb": true, + "commitlog_sync": true, + "commitlog_sync_batch_window_in_ms": true, + "commitlog_sync_group_window_in_ms": true, + "commitlog_sync_period_in_ms": true, + "commitlog_segment_size_in_mb": true, + "commitlog_compression": true, + "flush_compression": true, + "commitlog_max_compression_buffers_in_pool": true, + "periodic_commitlog_sync_lag_block_in_ms": true, + "transparent_data_encryption_options": true, + "max_mutation_size_in_kb": true, + "cdc_enabled": true, + "cdc_raw_directory": true, + "cdc_total_space_in_mb": true, + "cdc_free_space_check_interval_ms": true, + "commitlog_periodic_queue_size": true, + "endpoint_snitch": true, + "dynamic_snitch": true, + "dynamic_snitch_update_interval_in_ms": true, + "dynamic_snitch_reset_interval_in_ms": true, + "dynamic_snitch_badness_threshold": true, + "failure_detector": true, + "server_encryption_options": true, + "client_encryption_options": true, + "internode_compression": true, + "hinted_handoff_throttle_in_kb": true, + "batchlog_replay_throttle_in_kb": true, + "max_hints_delivery_threads": true, + "hints_flush_period_in_ms": true, + "max_hints_file_size_in_mb": true, + "hints_compression": true, + "auto_hints_cleanup_enabled": true, + "incremental_backups": true, + "trickle_fsync": true, + "trickle_fsync_interval_in_kb": true, + "sstable_preemptive_open_interval_in_mb": true, + "key_cache_migrate_during_compaction": true, + "key_cache_size_in_mb": true, + "key_cache_save_period": true, + "key_cache_keys_to_save": true, + "row_cache_class_name": true, + "row_cache_size_in_mb": true, + "row_cache_save_period": true, + "row_cache_keys_to_save": true, + "counter_cache_size_in_mb": true, + "counter_cache_save_period": true, + "counter_cache_keys_to_save": true, + "paxos_cache_size_in_mb": true, + "networking_cache_size_in_mb": true, + "file_cache_size_in_mb": true, + "file_cache_enabled": true, + "file_cache_round_up": true, + "buffer_pool_use_heap_if_exhausted": true, + "disk_optimization_strategy": true, + "disk_optimization_estimate_percentile": true, + "disk_optimization_page_cross_chance": true, + "inter_dc_tcp_nodelay": true, + "memtable_allocation_type": true, + "track_warnings": true, + "tombstone_warn_threshold": true, + "tombstone_failure_threshold": true, + "replica_filtering_protection": true, + "index_summary_capacity_in_mb": true, + "index_summary_resize_interval_in_minutes": true, + "gc_log_threshold_in_ms": true, + "gc_warn_threshold_in_ms": true, + "tracetype_query_ttl": true, + "tracetype_repair_ttl": true, + "ideal_consistency_level": true, + "otc_coalescing_strategy": true, + "otc_coalescing_window_us": true, + "otc_coalescing_enough_coalesced_messages": true, + "windows_timer_interval": true, + "prepared_statements_cache_size_mb": true, + "enable_user_defined_functions": true, + "enable_scripted_user_defined_functions": true, + "enable_materialized_views": true, + "enable_transient_replication": true, + "enable_sasi_indexes": true, + "enable_drop_compact_storage": true, + "enable_user_defined_functions_threads": true, + "user_defined_function_warn_timeout": true, + "user_defined_function_fail_timeout": true, + "user_function_timeout_policy": true, + "back_pressure_enabled": true, + "back_pressure_strategy": true, + "concurrent_validations": true, + "repair_command_pool_full_strategy": true, + "repair_command_pool_size": true, + "block_for_peers_timeout_in_secs": true, + "block_for_peers_in_remote_dcs": true, + "automatic_sstable_upgrade": true, + "max_concurrent_automatic_sstable_upgrades": true, + "stream_entire_sstables": true, + "audit_logging_options": true, + "full_query_logging_options": true, + "corrupted_tombstone_strategy": true, + "diagnostic_events_enabled": true, + "default_keyspace_rf": true, + "minimum_keyspace_rf": true, + "repaired_data_tracking_for_range_reads_enabled": true, + "repaired_data_tracking_for_partition_reads_enabled": true, + "report_unconfirmed_repaired_data_mismatches": true, + "snapshot_on_repaired_data_mismatch": true, + "validation_preview_purge_head_start_in_sec": true, + "auth_read_consistency_level": true, + "auth_write_consistency_level": true, + "enable_partition_denylist": true, + "enable_denylist_writes": true, + "enable_denylist_reads": true, + "enable_denylist_range_reads": true, + "denylist_refresh_seconds": true, + "denylist_initial_load_retry_seconds": true, + "denylist_max_keys_per_table": true, + "denylist_max_keys_total": true, + "denylist_consistency_level": true, + "initial_range_tombstone_list_allocation_size": true, + "range_tombstone_list_growth_factor": true, + "snapshot_on_duplicate_row_detection": true, + "check_for_duplicate_rows_during_reads": true, + "check_for_duplicate_rows_during_compaction": true, + "autocompaction_on_startup_enabled": true, + "auto_optimise_inc_repair_streams": true, + "auto_optimise_full_repair_streams": true, + "auto_optimise_preview_repair_streams": true, + "table_count_warn_threshold": true, + "keyspace_count_warn_threshold": true, + "consecutive_message_errors_threshold": true, + "client_error_reporting_exclusions": true, + "internode_error_reporting_exclusions": true, + }, + } +) diff --git a/apis/cassandra/v1beta1/cassandradatacenter_webhook.go b/apis/cassandra/v1beta1/cassandradatacenter_webhook.go index 035a22412..8668721a9 100644 --- a/apis/cassandra/v1beta1/cassandradatacenter_webhook.go +++ b/apis/cassandra/v1beta1/cassandradatacenter_webhook.go @@ -116,6 +116,13 @@ func ValidateSingleDatacenter(dc CassandraDatacenter) error { } } + if !isDse { + err := ValidateConfig(&dc) + if err != nil { + return err + } + } + return nil } @@ -226,3 +233,36 @@ func (dc *CassandraDatacenter) ValidateUpdate(old runtime.Object) error { func (dc *CassandraDatacenter) ValidateDelete() error { return nil } + +func ValidateConfig(dc *CassandraDatacenter) error { + // TODO Cleanup to more common processing after ModelValues is moved to apis + if dc.Spec.Config != nil { + var dcConfig map[string]interface{} + if err := json.Unmarshal(dc.Spec.Config, &dcConfig); err != nil { + return err + } + casYaml, found := dcConfig["cassandra-yaml"] + if !found { + return nil + } + + casYamlMap, ok := casYaml.(map[string]interface{}) + if !ok { + err := fmt.Errorf("failed to parse cassandra-yaml") + return err + } + + configValues, err := GetCassandraConfigValues(dc.Spec.ServerVersion) + if err != nil { + return err + } + + for k := range casYamlMap { + if !configValues.HasProperty(k) { + // We should probably add an event to tell the user that they're using old values + return fmt.Errorf("property %s is not valid for serverVersion %s", k, dc.Spec.ServerVersion) + } + } + } + return nil +} diff --git a/apis/cassandra/v1beta1/webhook_test.go b/apis/cassandra/v1beta1/webhook_test.go index f588edb0a..338acd24c 100644 --- a/apis/cassandra/v1beta1/webhook_test.go +++ b/apis/cassandra/v1beta1/webhook_test.go @@ -172,6 +172,48 @@ func Test_ValidateSingleDatacenter(t *testing.T) { }, errString: "attempted to define config jvm-server-options with cassandra-3.11.7", }, + { + name: "Cassandra 3.11 invalid cassandra-yaml full_query_options", + dc: &CassandraDatacenter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "exampleDC", + }, + Spec: CassandraDatacenterSpec{ + ServerType: "cassandra", + ServerVersion: "3.11.11", + Config: json.RawMessage(` + { + "cassandra-yaml": { + "full_query_logging_options": { + "log_dir": "/var/log/cassandra/fql" + } + } + } + `), + }, + }, + errString: "property full_query_logging_options is not valid for serverVersion 3.11.11", + }, + { + name: "Cassandra 4.0.1 invalid cassandra-yaml thrift_max_message_length_in_mb", + dc: &CassandraDatacenter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "exampleDC", + }, + Spec: CassandraDatacenterSpec{ + ServerType: "cassandra", + ServerVersion: "4.0.1", + Config: json.RawMessage(` + { + "cassandra-yaml": { + "thrift_max_message_length_in_mb": "256" + } + } + `), + }, + }, + errString: "property thrift_max_message_length_in_mb is not valid for serverVersion 4.0.1", + }, { name: "DSE 6.8 invalid config file jvm-options", dc: &CassandraDatacenter{ diff --git a/hack/config/Pipfile b/hack/config/Pipfile new file mode 100644 index 000000000..e77b372d4 --- /dev/null +++ b/hack/config/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +javalang = "*" + +[dev-packages] + +[requires] +python_version = "3.9" diff --git a/hack/config/generate.sh b/hack/config/generate.sh new file mode 100755 index 000000000..788453733 --- /dev/null +++ b/hack/config/generate.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +OUTPUTFILE=../../apis/cassandra/v1beta1/cassandra_config_generated.go +curl -sL https://raw.githubusercontent.com/apache/cassandra/cassandra-4.0/src/java/org/apache/cassandra/config/Config.java --output Config-40.java +curl -sL https://raw.githubusercontent.com/apache/cassandra/cassandra-3.11/src/java/org/apache/cassandra/config/Config.java --output Config-311.java +curl -sL https://raw.githubusercontent.com/apache/cassandra/trunk/src/java/org/apache/cassandra/config/Config.java --output Config-trunk.java +pipenv run python parse.py > $OUTPUTFILE +go fmt $OUTPUTFILE +rm -f *.java \ No newline at end of file diff --git a/hack/config/parse.py b/hack/config/parse.py new file mode 100644 index 000000000..5b8acb3df --- /dev/null +++ b/hack/config/parse.py @@ -0,0 +1,85 @@ +# This script generates golang structs for Cassandra configurations +import javalang +from pathlib import Path +from typing import List + +def parse_file(file: str): + config_file = Path(file).read_text() + tree = javalang.parse.parse(config_file) + for path, node in tree.filter(javalang.tree.ClassDeclaration): + if node.name == "Config": + for field in node.fields: + if 'public' in field.modifiers and not 'static' in field.modifiers: + for declarator in field.declarators: + print(f'"{declarator.name}": true,') + # for annotation in field.annotations: + # if annotation.name == "Deprecated": + # print('Deprecated!') + +def generate_configs(versions: List[str]): + print(""" +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code is generated with hack/config. DO NOT EDIT. +package v1beta1 + +import ( + "strconv" + "strings" +) + +type CassandraConfigValues struct { + accepted map[string]interface{} +} + +func (c *CassandraConfigValues) HasProperty(propertyName string) bool { + _, found := c.accepted[propertyName] + return found +} + +func GetCassandraConfigValues(serverVersion string) (*CassandraConfigValues, error) { + versionParts := strings.Split(serverVersion, ".") + serverMajorVersion, err := strconv.ParseInt(versionParts[0], 10, 8) + if err != nil { + return nil, err + } + + if serverMajorVersion == 3 { + // Return configuration for 3.11, regardless of the real version (we don't support <3.11) + return &config311, nil + } + + if serverMajorVersion == 4 { + serverMinorVersion, err := strconv.ParseInt(versionParts[1], 10, 8) + if err != nil { + return nil, err + } + if serverMinorVersion == 0 { + // Return config40 + return &config40, nil + } + } + // Something brand new.. + return &configtrunk, nil +} + + var( + """) + + for ver in versions: + create_config_values(ver) + + print(')') + +def create_config_values(version: str): + print(f""" + config{version} = CassandraConfigValues{{ + accepted: map[string]interface{{}}{{""") + parse_file(f'Config-{version}.java') + print(""" + }, + } + """) + +generate_configs(['311', '40', 'trunk']) diff --git a/hack/kind-reload-operator.sh b/hack/kind-reload-operator.sh deleted file mode 100755 index 01f791ed1..000000000 --- a/hack/kind-reload-operator.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -all_ids=(`docker container ls | egrep kindest | cut -d ' ' -f 1`) -for id in ${all_ids[*]} -do - echo "Deleting old operator Docker image from Docker container: $id" - docker exec $id crictl rmi docker.io/datastax/cass-operator:latest -done -echo "Loading new operator Docker image into KIND cluster" -kind load docker-image datastax/cass-operator:latest -echo "Done." diff --git a/hack/release/build-kind-control-planes.sh b/hack/release/build-kind-control-planes.sh deleted file mode 100755 index 7fa9fcdd1..000000000 --- a/hack/release/build-kind-control-planes.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -set -euf -o pipefail -set -x - -kind create cluster --image kindest/node:v1.15.12 --name k-1-15 -hack/release/make-yaml-bundle.sh -kubectl apply -f docs/user/cass-operator-manifests-v1.15.yaml -kind delete cluster --name k-1-15 - -kind create cluster --image kindest/node:v1.16.15 --name k-1-16 -hack/release/make-yaml-bundle.sh -kubectl apply -f docs/user/cass-operator-manifests-v1.16.yaml -kind delete cluster --name k-1-16 - -kind create cluster --image kindest/node:v1.17.11 --name k-1-17 -hack/release/make-yaml-bundle.sh -kubectl apply -f docs/user/cass-operator-manifests-v1.17.yaml -kind delete cluster --name k-1-17 - -kind create cluster --image kindest/node:v1.18.8 --name k-1-18 -hack/release/make-yaml-bundle.sh -kubectl apply -f docs/user/cass-operator-manifests-v1.18.yaml -kind delete cluster --name k-1-18 - -kind create cluster --image kindest/node:v1.19.1 --name k-1-19 -hack/release/make-yaml-bundle.sh -kubectl apply -f docs/user/cass-operator-manifests-v1.19.yaml -kind delete cluster --name k-1-19 diff --git a/hack/release/check-chart-sources.sh b/hack/release/check-chart-sources.sh deleted file mode 100755 index 520a67d2f..000000000 --- a/hack/release/check-chart-sources.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -set -euf -o pipefail -set -x - -# uses diff-so-fancy from https://github.com/so-fancy/diff-so-fancy - -opDeploy="operator/deploy" -chartTmpl="charts/cass-operator-chart/templates" -chartCrd="charts/cass-operator-chart/crds" -crdFilename="cassandra.datastax.com_cassandradatacenters_crd.yaml" - -diff -u $opDeploy/role.yaml $chartTmpl/role.yaml | diff-so-fancy || true -diff -u $opDeploy/role_binding.yaml $chartTmpl/rolebinding.yaml | diff-so-fancy || true -diff -u $opDeploy/cluster_role.yaml $chartTmpl/clusterrole.yaml | diff-so-fancy || true -diff -u $opDeploy/cluster_role_binding.yaml $chartTmpl/clusterrolebinding.yaml | diff-so-fancy || true -diff -u $opDeploy/service_account.yaml $chartTmpl/serviceaccount.yaml | diff-so-fancy || true -diff -u $opDeploy/webhook_configuration.yaml $chartTmpl/validatingwebhookconfiguration.yaml | diff-so-fancy || true -diff -u $opDeploy/operator.yaml $chartTmpl/deployment.yaml | diff-so-fancy || true -diff -u $opDeploy/webhook_service.yaml $chartTmpl/service.yaml | diff-so-fancy || true -diff -u $opDeploy/webhook_secret.yaml $chartTmpl/secret.yaml | diff-so-fancy || true -diff -u $opDeploy/crds/$crdFilename $chartTmpl/customresourcedefinition.yaml | diff-so-fancy || true diff --git a/hack/release/make-yaml-bundle.sh b/hack/release/make-yaml-bundle.sh deleted file mode 100755 index aca2bb07c..000000000 --- a/hack/release/make-yaml-bundle.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -euf -o pipefail -set -x - -# uses helm v3.1.2, kubectl v1.18.2, yq v3.2.1 - -bundle="$(mktemp)" - -k8sVer="$(kubectl version --short | grep Server | egrep -o 'v[0-9].[0-9]+')" - -echo '---' >> "$bundle" -cat operator/deploy/namespace.yaml | yq eval - >> "$bundle" - -echo '---' >> "$bundle" -helm template ./charts/cass-operator-chart/ -n cass-operator --validate=true | kubectl create --dry-run=client -o yaml -n cass-operator -f - >> "$bundle" - -mv "$bundle" docs/user/cass-operator-manifests-$k8sVer.yaml diff --git a/hack/run_kubefwd.sh b/hack/run_kubefwd.sh deleted file mode 100755 index c1bb67067..000000000 --- a/hack/run_kubefwd.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# This script will run kubefwd in an infinite loop, restarting every 20 seconds in order to forward -# the latest pods and services. - -# Kubefwd can be installed from https://github.com/txn2/kubefwd - -which kubefwd >/dev/null || { echo "Please install kubefwd"; exit 1; } - -while true; do - # Since kubefwd updates /etc/hosts file it has to be ran as sudo - sudo kubefwd svc & q_pid="${!}" - ( sleep 20 ; sudo kill "${q_pid}" ) & s_pid="${!}" - wait "${q_pid}" - sudo kill "${s_pid}" - wait "${s_pid}" -done diff --git a/pkg/reconciliation/handler.go b/pkg/reconciliation/handler.go index 7f263f198..c30746523 100644 --- a/pkg/reconciliation/handler.go +++ b/pkg/reconciliation/handler.go @@ -203,6 +203,9 @@ func (rc *ReconciliationContext) IsValid(dc *api.CassandraDatacenter) error { // validate any other defined users errs = append(errs, rc.validateCassandraUserSecrets()...) + // Validate spec.Config + errs = append(errs, api.ValidateConfig(dc)) + // Validate Management API config errs = append(errs, httphelper.ValidateManagementApiConfig(dc, rc.Client, rc.Ctx)...) if len(errs) > 0 {