diff --git a/manifests/params.pp b/manifests/params.pp index fb461de..c94f127 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -1,58 +1,60 @@ # This class is meant to be called from the locp-cassandra module. # It sets variables according to platform. class cassandra::params { case $::osfamily { 'Debian': { case $::operatingsystemmajrelease { '12.04': { $net_ipv4_tcp_rmem = '4096 87380 16777216' $net_ipv4_tcp_wmem = '4096 65536 16777216' $java_package = 'openjdk-7-jre-headless' } '18.04': { $net_ipv4_tcp_rmem = '4096 87380 16777216' $net_ipv4_tcp_wmem = '4096 65536 16777216' $java_package = 'openjdk-8-jre-headless' } # non-Ubuntu Debian is just... Debian default: { $net_ipv4_tcp_rmem = '4096, 87380, 16777216' $net_ipv4_tcp_wmem = '4096, 65536, 16777216' $java_package = 'openjdk-7-jre-headless' } } $cassandra_pkg = 'cassandra' $config_path = '/etc/cassandra' $jna_package_name = 'libjna-java' $optutils_package_name = 'cassandra-tools' $sysctl_file = '/etc/sysctl.d/10-cassandra.conf' $systemctl = '/bin/systemctl' } 'RedHat': { case $::operatingsystemmajrelease { 6: { $net_ipv4_tcp_rmem = '4096 87380 16777216' $net_ipv4_tcp_wmem = '4096 65536 16777216' $sysctl_file = '/etc/sysctl.conf' } 7: { $net_ipv4_tcp_rmem = '4096, 87380, 16777216' $net_ipv4_tcp_wmem = '4096, 65536, 16777216' $sysctl_file = '/etc/sysctl.d/10-cassandra.conf' } default: {} } $cassandra_pkg = 'cassandra22' $config_path = '/etc/cassandra/default.conf' $java_package = 'java-1.8.0-openjdk-headless' $jna_package_name = 'jna' $optutils_package_name = 'cassandra22-tools' $systemctl = '/usr/bin/systemctl' + $use_scl = false + $scl_name = 'nodefault' } default: { $config_path_parents = [] } } } diff --git a/manifests/schema.pp b/manifests/schema.pp index da37de0..0de2e53 100644 --- a/manifests/schema.pp +++ b/manifests/schema.pp @@ -1,128 +1,147 @@ # A class to maintain the database schema. Please note that cqlsh expects # Python 2.7 to be installed. This may be a problem of older distributions # (CentOS 6 for example). # @param connection_tries [integer] How many times do try to connect to # Cassandra. See also `connection_try_sleep`. # @param connection_try_sleep [integer] How much time to allow between the # number of tries specified in `connection_tries`. # @param cql_types [hash] Creates new `cassandra::schema::cql_type` resources. # @param cqlsh_additional_options [string] Any additional options to be passed # to the `cqlsh` command. # @param cqlsh_client_config [string] Set this to a file name # (e.g. '/root/.puppetcqlshrc') that will then be used to contain the # the credentials for connecting to Cassandra. This is a more secure option # than having the credentials appearing on the command line. This option # is only available in Cassandra >= 2.1. # @param cqlsh_client_tmpl [string] The location of the template for configuring # the credentials for the cqlsh client. This is ignored unless # `cqlsh_client_config` is set. # @param cqlsh_command [string] The full path to the `cqlsh` command. # @param cqlsh_host [string] The host for the `cqlsh` command to connect to. # See also `cqlsh_port`. # @param cqlsh_password [string] If credentials are require for connecting, # specify the password here. See also `cqlsh_user`, `cqlsh_client_config`. # @param cqlsh_port [integer] The host for the `cqlsh` command to connect to. # See also `cqlsh_host`. # @param cqlsh_user [string] If credentials are required for connecting, # specify the password here. See also `cqlsh_password`, # `cqlsh_client_config` # @param indexes [hash] Creates new `cassandra::schema::index` resources. # @param keyspaces [hash] Creates new `cassandra::schema::keyspace` resources. # @param permissions [hash] Creates new `cassandra::schema::permission` # resources. # @param tables [hash] Creates new `cassandra::schema::table` resources. # @param users [hash] Creates new `cassandra::schema::user` resources. class cassandra::schema ( $connection_tries = 6, $connection_try_sleep = 30, $cql_types = {}, $cqlsh_additional_options = '', $cqlsh_client_config = undef, $cqlsh_client_tmpl = 'cassandra/cqlshrc.erb', $cqlsh_command = '/usr/bin/cqlsh', $cqlsh_host = 'localhost', $cqlsh_password = undef, $cqlsh_port = 9042, $cqlsh_user = 'cassandra', $indexes = {}, $keyspaces = {}, $permissions = {}, $tables = {}, $users = {}, + $use_scl = $::cassandra::params::use_scl, + $scl_name = $::cassandra::params::scl_name, ) inherits cassandra::params { require '::cassandra' + # Test that the SCL is valid + if $use_scl { + exec { "test ${scl_name} SCL": + command => "/usr/bin/scl enable ${scl_name} \"echo test\"", + } + $scl_require = Exec["test ${scl_name} SCL"] + } else { + $scl_require = undef + } + + # Pass the SCL info to create_resources below as a hash + $scl = { + 'use_scl' => $use_scl, + 'scl_name' => $scl_name, + } + if $cqlsh_client_config != undef { file { $cqlsh_client_config : ensure => file, group => $::gid, mode => '0600', owner => $::id, content => template( $cqlsh_client_tmpl ), before => Exec['::cassandra::schema connection test'], } $cmdline_login = "--cqlshrc=${cqlsh_client_config}" } else { if $cqlsh_password != undef { warning('You may want to consider using the cqlsh_client_config attribute') $cmdline_login = "-u ${cqlsh_user} -p ${cqlsh_password}" } else { $cmdline_login = '' } } $cqlsh_opts = "${cqlsh_command} ${cmdline_login} ${cqlsh_additional_options}" $cqlsh_conn = "${cqlsh_host} ${cqlsh_port}" # See if we can make a connection to Cassandra. Try $connection_tries # number of times with $connection_try_sleep in seconds between each try. $connection_test = "${cqlsh_opts} -e 'DESC KEYSPACES' ${cqlsh_conn}" exec { '::cassandra::schema connection test': command => $connection_test, returns => 0, tries => $connection_tries, try_sleep => $connection_try_sleep, unless => $connection_test, + require => $scl_require, } # manage keyspaces if present if $keyspaces { - create_resources('cassandra::schema::keyspace', $keyspaces) + create_resources('cassandra::schema::keyspace', $keyspaces, $scl) } # manage cql_types if present if $cql_types { - create_resources('cassandra::schema::cql_type', $cql_types) + create_resources('cassandra::schema::cql_type', $cql_types, $scl) } # manage tables if present if $tables { - create_resources('cassandra::schema::table', $tables) + create_resources('cassandra::schema::table', $tables, $scl) } # manage indexes if present if $indexes { - create_resources('cassandra::schema::index', $indexes) + create_resources('cassandra::schema::index', $indexes, $scl) } # manage users if present if $users { - create_resources('cassandra::schema::user', $users) + create_resources('cassandra::schema::user', $users, $scl) } # manage permissions if present if $permissions { - create_resources('cassandra::schema::permission', $permissions) + create_resources('cassandra::schema::permission', $permissions, $scl) } # Resource Ordering Cassandra::Schema::Keyspace <| |> -> Cassandra::Schema::Cql_type <| |> Cassandra::Schema::Keyspace <| |> -> Cassandra::Schema::Table <| |> Cassandra::Schema::Keyspace <| |> -> Cassandra::Schema::Permission <| |> Cassandra::Schema::Cql_type <| |> -> Cassandra::Schema::Table <| |> Cassandra::Schema::Table <| |> -> Cassandra::Schema::Index <| |> Cassandra::Schema::Table <| |> -> Cassandra::Schema::Permission <| |> Cassandra::Schema::Index <| |> -> Cassandra::Schema::User <| |> Cassandra::Schema::User <| |> -> Cassandra::Schema::Permission <| |> } diff --git a/manifests/schema/cql_type.pp b/manifests/schema/cql_type.pp index 961986a..b952bc0 100644 --- a/manifests/schema/cql_type.pp +++ b/manifests/schema/cql_type.pp @@ -1,43 +1,45 @@ # Create or drop user defined data types within the schema. # @param keyspace [string] The name of the keyspace that the data type is to be associated with. # @param ensure [present|absent] ensure the data type is created, or is dropped. # @param fields [hash] A hash of the fields that will be components for the data type. # @param cql_type_name [string] The name of the CQL type to be created. # @example # cassandra::schema::cql_type { 'fullname': # keyspace => 'mykeyspace', # fields => { # 'fname' => 'text', # 'lname' => 'text', # }, # } define cassandra::schema::cql_type ( $keyspace, $ensure = present, $fields = {}, $cql_type_name = $title, + $use_scl = $::cassandra::params::use_scl, + $scl_name = $::cassandra::params::scl_name, ){ include 'cassandra::schema' $read_script = "DESC TYPE ${keyspace}.${cql_type_name}" $read_command = "${::cassandra::schema::cqlsh_opts} -e \"${read_script}\" ${::cassandra::schema::cqlsh_conn}" if $ensure == present { $create_script1 = "CREATE TYPE IF NOT EXISTS ${keyspace}.${cql_type_name}" $create_script2 = join(join_keys_to_values($fields, ' '), ', ') $create_script = "${create_script1} (${create_script2})" $create_command = "${::cassandra::schema::cqlsh_opts} -e \"${create_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $create_command: unless => $read_command, require => Exec['::cassandra::schema connection test'], } } elsif $ensure == absent { $delete_script = "DROP type ${keyspace}.${cql_type_name}" $delete_command = "${::cassandra::schema::cqlsh_opts} -e \"${delete_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $delete_command: onlyif => $read_command, require => Exec['::cassandra::schema connection test'], } } else { fail("Unknown action (${ensure}) for ensure attribute.") } } diff --git a/manifests/schema/index.pp b/manifests/schema/index.pp index c5efce1..13fcdf4 100644 --- a/manifests/schema/index.pp +++ b/manifests/schema/index.pp @@ -1,67 +1,69 @@ # Create or drop indexes within the schema. # @param ensure [present|absent] Create or dro[ the index. # @param class_name [string] The name of the class to be associated with an # index when creating a custom index. # @param index [string] The name of the index. Defaults to the name of the # resource. # @param keys [string] The columns that the index is being created on. # @param keyspace [string] The name the keyspace that the index is to be associated # with. # @param options [string] Any options to be added to the index. # @param table [string] The name of the table that the index is to be associated with. define cassandra::schema::index( $keyspace, $table, $ensure = present, $class_name = undef, $index = $title, $keys = undef, $options = undef, + $use_scl = $::cassandra::params::use_scl, + $scl_name = $::cassandra::params::scl_name, ) { include 'cassandra::schema' # Fully qualified index name. $fqin = "${keyspace}.${index}" # Fully qualified table name. $fqtn = "${keyspace}.${table}" $read_script = "DESC INDEX ${fqin}" $read_command = "${::cassandra::schema::cqlsh_opts} -e \"${read_script}\" ${::cassandra::schema::cqlsh_conn}" if $ensure == present { if $class_name != undef { $create_part1 = "CREATE CUSTOM INDEX IF NOT EXISTS ${index} ON ${keyspace}.${table}" } else { $create_part1 = "CREATE INDEX IF NOT EXISTS ${index} ON ${keyspace}.${table}" } if $class_name != undef { $create_part2 = "${create_part1} (${keys}) USING '${class_name}'" } else { $create_part2 = "${create_part1} (${keys})" } if $options != undef { $create_script = "${create_part2} WITH OPTIONS = ${options}" } else { $create_script = $create_part2 } $create_command = "${::cassandra::schema::cqlsh_opts} -e \"${create_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $create_command: unless => $read_command, require => Exec['::cassandra::schema connection test'], } } elsif $ensure == absent { $delete_script = "DROP INDEX ${fqin}" $delete_command = "${::cassandra::schema::cqlsh_opts} -e \"${delete_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $delete_command: onlyif => $read_command, require => Exec['::cassandra::schema connection test'], } } else { fail("Unknown action (${ensure}) for ensure attribute.") } } diff --git a/manifests/schema/keyspace.pp b/manifests/schema/keyspace.pp index f42e637..2e5bcde 100644 --- a/manifests/schema/keyspace.pp +++ b/manifests/schema/keyspace.pp @@ -1,76 +1,78 @@ # Create or drop keyspaces within the schema. # @param ensure [present|absent] Create or drop the keyspace. # @param durable_writes [boolean] When set to false, data written to the # keyspace bypasses the commit log. Be careful using this option # because you risk losing data. Set this attribute to false on a keyspace # using the SimpleStrategy. # @param keyspace_name [string] The name of the keyspace to be created. # @param replication_map [hash] Needed if the keyspace is to be present. # Optional if it is to be absent. # @example # $network_topology_strategy = { # keyspace_class => 'NetworkTopologyStrategy', # dc1 => 3, # dc2 => 2 # } # @example # cassandra::schema::keyspace { 'mykeyspace': # replication_map => { # keyspace_class => 'SimpleStrategy', # replication_factor => 1, # }, # durable_writes => false, # } define cassandra::schema::keyspace( $ensure = present, $durable_writes = true, $keyspace_name = $title, $replication_map = {}, + $use_scl = $::cassandra::params::use_scl, + $scl_name = $::cassandra::params::scl_name, ) { include 'cassandra::schema' $read_script = "DESC KEYSPACE ${keyspace_name}" $read_command = "${::cassandra::schema::cqlsh_opts} -e \"${read_script}\" ${::cassandra::schema::cqlsh_conn}" if $ensure == present { $keyspace_class = $replication_map[keyspace_class] case $keyspace_class { 'SimpleStrategy': { $replication_factor = $replication_map[replication_factor] $map_str = "{ 'class' : 'SimpleStrategy', 'replication_factor' : ${replication_factor} }" } 'NetworkTopologyStrategy': { $map_str1 = "{ 'class' : 'NetworkTopologyStrategy'" $new_map = prefix(delete($replication_map, 'keyspace_class'), "'") $map_str2 = join(join_keys_to_values($new_map, "': "), ', ') $map_str = "${map_str1}, ${map_str2} }" } default: { $msg_part1 = "Invalid or no class (${keyspace_class}) specified for" $msg_part2 = "keyspace ${keyspace_name}." fail("${msg_part1} ${msg_part2}") } } $create_script1 = "CREATE KEYSPACE IF NOT EXISTS ${keyspace_name}" $create_script2 = "WITH REPLICATION = ${map_str}" $create_script3 = "AND DURABLE_WRITES = ${durable_writes}" $create_script = "${create_script1} ${create_script2} ${create_script3}" $create_command = "${::cassandra::schema::cqlsh_opts} -e \"${create_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $create_command: unless => $read_command, require => Exec['::cassandra::schema connection test'], } } elsif $ensure == absent { $delete_script = "DROP KEYSPACE ${keyspace_name}" $delete_command = "${::cassandra::schema::cqlsh_opts} -e \"${delete_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $delete_command: onlyif => $read_command, require => Exec['::cassandra::schema connection test'], } } else { fail("Unknown action (${ensure}) for ensure attribute.") } } diff --git a/manifests/schema/permission.pp b/manifests/schema/permission.pp index 1dfbea3..d6edb26 100644 --- a/manifests/schema/permission.pp +++ b/manifests/schema/permission.pp @@ -1,127 +1,129 @@ # Grant or revoke permissions. # To use this class, a suitable `authenticator` (e.g. PasswordAuthenticator) # and `authorizer` (e.g. CassandraAuthorizer) must be set in the Cassandra # class. # # WARNING: Specifying keyspace 'ALL' and 'ALL' for permissions at the same # time is not currently supported by this module. # # @param user_name [string] The name of the user who is to be granted or # revoked. # @param ensure [ present | absent ] Set to present to grant a permission or # absent to revoke it. # @param keyspace_name [string] The name of the keyspace to grant/revoke the # permissions on. If set to 'ALL' then the permission will be applied to # all of the keyspaces. # @param permission_name [string] Can be one of the following: # # * 'ALTER' - ALTER KEYSPACE, ALTER TABLE, CREATE INDEX, DROP INDEX. # * 'AUTHORIZE' - GRANT, REVOKE. # * 'CREATE' - CREATE KEYSPACE, CREATE TABLE. # * 'DROP' - DROP KEYSPACE, DROP TABLE. # * 'MODIFY' - INSERT, DELETE, UPDATE, TRUNCATE. # * 'SELECT' - SELECT. # # If the permission_name is set to 'ALL', this will set all of the specific # permissions listed. # @param table_name [string] The name of a table within the specified # keyspace. If left unspecified, the procedure will be applied to all # tables within the keyspace. define cassandra::schema::permission ( $user_name, $ensure = present, $keyspace_name = 'ALL', $permission_name = 'ALL', $table_name = undef, + $use_scl = $::cassandra::params::use_scl, + $scl_name = $::cassandra::params::scl_name, ){ include 'cassandra::schema' if upcase($keyspace_name) == 'ALL' and upcase($permission_name) == 'ALL' { fail('"ALL" keyspaces AND "ALL" permissions are mutually exclusive.') } elsif $table_name { $resource = "TABLE ${keyspace_name}.${table_name}" } elsif upcase($keyspace_name) == 'ALL' { $resource = 'ALL KEYSPACES' } else { $resource = "KEYSPACE ${keyspace_name}" } $read_script = "LIST ALL PERMISSIONS ON ${resource}" $upcase_permission_name = upcase($permission_name) $pattern = "\s${user_name} |\s*${user_name} |\s.*\s${upcase_permission_name}$" $read_command = "${::cassandra::schema::cqlsh_opts} -e \"${read_script}\" ${::cassandra::schema::cqlsh_conn} | grep '${pattern}'" if upcase($permission_name) == 'ALL' { cassandra::schema::permission { "${title} - ALTER": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'ALTER', table_name => $table_name, } cassandra::schema::permission { "${title} - AUTHORIZE": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'AUTHORIZE', table_name => $table_name, } # The CREATE permission is not relevant to tables. if !$table_name { cassandra::schema::permission { "${title} - CREATE": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'CREATE', table_name => $table_name, } } cassandra::schema::permission { "${title} - DROP": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'DROP', table_name => $table_name, } cassandra::schema::permission { "${title} - MODIFY": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'MODIFY', table_name => $table_name, } cassandra::schema::permission { "${title} - SELECT": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'SELECT', table_name => $table_name, } } elsif $ensure == present { $create_script = "GRANT ${permission_name} ON ${resource} TO ${user_name}" $create_command = "${::cassandra::schema::cqlsh_opts} -e \"${create_script}\" ${::cassandra::schema::cqlsh_conn }" exec { $create_script: command => $create_command, unless => $read_command, require => Exec['::cassandra::schema connection test'], } } elsif $ensure == absent { $delete_script = "REVOKE ${permission_name} ON ${resource} FROM ${user_name}" $delete_command = "${::cassandra::schema::cqlsh_opts} -e \"${delete_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $delete_script: command => $delete_command, onlyif => $read_command, require => Exec['::cassandra::schema connection test'], } } else { fail("Unknown action (${ensure}) for ensure attribute.") } } diff --git a/manifests/schema/table.pp b/manifests/schema/table.pp index b59f5cd..eb1efa0 100644 --- a/manifests/schema/table.pp +++ b/manifests/schema/table.pp @@ -1,57 +1,59 @@ # Create or drop tables within the schema. # @param keyspace [string] The name of the keyspace. # @param columns [hash] A hash of the columns to be placed in the table. # Optional if the table is to be absent. # @param ensure [present|absent] Ensure a keyspace is created or dropped. # @param options [array] Options to be added to the table creation. # @param table [string] The name of the table. Defaults to the name of the # resource. # @example # cassandra::schema::table { 'users': # keyspace => 'mykeyspace', # columns => { # 'userid' => 'int', # 'fname' => 'text', # 'lname' => 'text', # 'PRIMARY KEY' => '(userid)', # }, # } define cassandra::schema::table ( $keyspace, $ensure = present, $columns = {}, $options = [], $table = $title, + $use_scl = $::cassandra::params::use_scl, + $scl_name = $::cassandra::params::scl_name, ){ include 'cassandra::schema' $read_script = "DESC TABLE ${keyspace}.${table}" $read_command = "${::cassandra::schema::cqlsh_opts} -e \"${read_script}\" ${::cassandra::schema::cqlsh_conn}" if $ensure == present { $create_script1 = "CREATE TABLE IF NOT EXISTS ${keyspace}.${table}" $cols_def = join(join_keys_to_values($columns, ' '), ', ') $cols_def_rm_collection_type = delete($cols_def, 'COLLECTION-TYPE ') if count($options) > 0 { $options_def = join($options, ' AND ') $create_script = "${create_script1} (${cols_def_rm_collection_type}) WITH ${options_def}" } else { $create_script = "${create_script1} (${cols_def_rm_collection_type})" } $create_command = "${::cassandra::schema::cqlsh_opts} -e \"${create_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $create_command: unless => $read_command, require => Exec['::cassandra::schema connection test'], } } elsif $ensure == absent { $delete_script = "DROP TABLE IF EXISTS ${keyspace}.${table}" $delete_command = "${::cassandra::schema::cqlsh_opts} -e \"${delete_script}\" ${::cassandra::schema::cqlsh_conn}" exec { $delete_command: onlyif => $read_command, require => Exec['::cassandra::schema connection test'], } } else { fail("Unknown action (${ensure}) for ensure attribute.") } } diff --git a/manifests/schema/user.pp b/manifests/schema/user.pp index 00a4ce6..4387988 100644 --- a/manifests/schema/user.pp +++ b/manifests/schema/user.pp @@ -1,115 +1,117 @@ # Create or drop users. # To use this class, a suitable `authenticator` (e.g. PasswordAuthenticator) # must be set in the Cassandra class. # @param ensure [ present | absent ] Valid values can be **present** to # ensure a user is created, or **absent** to remove the user if it exists. # @param password [string] A password for the user. # @param superuser [boolean] If the user is to be a super-user on the system. # @param login [boolean] Allows the role to log in. # @param user_name [string] The name of the user. # @example # cassandra::schema::user { 'akers': # password => 'Niner2', # superuser => true, # } # # cassandra::schema::user { 'lucan': # ensure => absent, # } define cassandra::schema::user ( $ensure = present, $login = true, $password = undef, $superuser = false, $user_name = $title, + $use_scl = $::cassandra::params::use_scl, + $scl_name = $::cassandra::params::scl_name, ){ include 'cassandra::schema' if $::cassandrarelease != undef { if versioncmp($::cassandrarelease, '2.2') < 0 { $operate_with_roles = false } else { $operate_with_roles = true } } else { $operate_with_roles = false } if $operate_with_roles { $read_script = 'LIST ROLES' } else { $read_script = 'LIST USERS' } $read_command = "${::cassandra::schema::cqlsh_opts} -e \"${read_script}\" ${::cassandra::schema::cqlsh_conn} | grep '\s*${user_name} |'" if $ensure == present { if $operate_with_roles { # we are running cassandra > 2.2 $create_script1 = "CREATE ROLE IF NOT EXISTS ${user_name}" if $password != undef { $create_script2 = "${create_script1} WITH PASSWORD = '${password}'" } else { $create_script2 = $create_script1 } if $superuser { if $password != undef { $create_script3 = "${create_script2} AND SUPERUSER = true" } else { $create_script3 = "${create_script2} WITH SUPERUSER = true" } } else { $create_script3 = $create_script2 } if $login { if $superuser or $password != undef { $create_script = "${create_script3} AND LOGIN = true" } else { $create_script = "${create_script3} WITH LOGIN = true" } } else { $create_script = $create_script3 } } else { $create_script1 = "CREATE USER IF NOT EXISTS ${user_name}" if $password != undef { $create_script2 = "${create_script1} WITH PASSWORD '${password}'" } else { $create_script2 = $create_script1 } if $superuser { $create_script = "${create_script2} SUPERUSER" } else { $create_script = "${create_script2} NOSUPERUSER" } } $create_command = "${::cassandra::schema::cqlsh_opts} -e \"${create_script}\" ${::cassandra::schema::cqlsh_conn}" exec { "Create user (${user_name})": command => $create_command, unless => $read_command, require => Exec['::cassandra::schema connection test'], } } elsif $ensure == absent { if $operate_with_roles { $delete_script = "DROP ROLE ${user_name}" } else { $delete_script = "DROP USER ${user_name}" } $delete_command = "${::cassandra::schema::cqlsh_opts} -e \"${delete_script}\" ${::cassandra::schema::cqlsh_conn}" exec { "Delete user (${user_name})": command => $delete_command, onlyif => $read_command, require => Exec['::cassandra::schema connection test'], } } else { fail("Unknown action (${ensure}) for ensure attribute.") } } diff --git a/spec/classes/schema_spec.rb b/spec/classes/schema_spec.rb index d468623..61a6400 100644 --- a/spec/classes/schema_spec.rb +++ b/spec/classes/schema_spec.rb @@ -1,131 +1,135 @@ require 'spec_helper' describe 'cassandra::schema' do context 'Ensure that a connection test is made.' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end it do is_expected.to contain_class('cassandra::schema'). with(connection_tries: 6, connection_try_sleep: 30, cqlsh_additional_options: '', cqlsh_command: '/usr/bin/cqlsh', cqlsh_host: 'localhost', cqlsh_password: nil, cqlsh_port: 9042, cqlsh_user: 'cassandra') read_command = '/usr/bin/cqlsh -e \'DESC KEYSPACES\' localhost 9042' is_expected.to contain_exec('::cassandra::schema connection test'). only_with(command: read_command, returns: 0, tries: 6, try_sleep: 30, unless: read_command) end end context 'Test that users can specify a credentials file.' do let :facts do { id: 'root', gid: 'root', operatingsystemmajrelease: 7, osfamily: 'Debian' } end let :params do { - cqlsh_client_config: '/root/.puppetcqlshrc' + cqlsh_client_config: '/root/.puppetcqlshrc', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to contain_file('/root/.puppetcqlshrc').with( ensure: 'file', group: 'root', mode: '0600', owner: 'root', content: %r{username = cassandra} ).that_comes_before('Exec[::cassandra::schema connection test]') read_command = "/usr/bin/cqlsh --cqlshrc=/root/.puppetcqlshrc -e 'DESC KEYSPACES' localhost 9042" is_expected.to contain_exec('::cassandra::schema connection test'). only_with(command: read_command, returns: 0, tries: 6, try_sleep: 30, unless: read_command) end end context 'Test that users can specify a credentials file and password.' do let :facts do { id: 'root', gid: 'root', operatingsystemmajrelease: 7, osfamily: 'Debian' } end let :params do { cqlsh_client_config: '/root/.puppetcqlshrc', - cqlsh_password: 'topsecret' + cqlsh_password: 'topsecret', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to contain_file('/root/.puppetcqlshrc').with( ensure: 'file', group: 'root', mode: '0600', owner: 'root', content: %r{password = topsecret} ) read_command = "/usr/bin/cqlsh --cqlshrc=/root/.puppetcqlshrc -e 'DESC KEYSPACES' localhost 9042" is_expected.to contain_exec('::cassandra::schema connection test'). only_with(command: read_command, returns: 0, tries: 6, try_sleep: 30, unless: read_command) end end context 'Test that users can specify a password.' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'Redhat' } end let :params do { cqlsh_password: 'topsecret' } end it do read_command = "/usr/bin/cqlsh -u cassandra -p topsecret -e 'DESC KEYSPACES' localhost 9042" is_expected.to contain_exec('::cassandra::schema connection test'). only_with(command: read_command, returns: 0, tries: 6, try_sleep: 30, unless: read_command) end end end diff --git a/spec/defines/schema/cql_type_spec.rb b/spec/defines/schema/cql_type_spec.rb index 9e9b4ee..61c93a0 100644 --- a/spec/defines/schema/cql_type_spec.rb +++ b/spec/defines/schema/cql_type_spec.rb @@ -1,73 +1,77 @@ require 'spec_helper' describe 'cassandra::schema::cql_type' do context 'CQL TYPE (fullname)' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'fullname' } let(:params) do { 'keyspace' => 'Excelsior', fields: { 'firstname' => 'text', 'lastname' => 'text' - } + }, + 'use_scl' => false, + 'scl_name' => 'nodefault' } end it do is_expected.to compile is_expected.to contain_class('cassandra::schema') is_expected.to contain_cassandra__schema__cql_type('fullname') is_expected.to contain_exec('/usr/bin/cqlsh -e "CREATE TYPE IF NOT EXISTS Excelsior.fullname (firstname text, lastname text)" localhost 9042') end end context 'Set ensure to absent' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'address' } let(:params) do { 'ensure' => 'absent', - 'keyspace' => 'Excalibur' + 'keyspace' => 'Excalibur', + 'use_scl' => false, + 'scl_name' => 'nodefault' } end it do is_expected.to compile is_expected.to contain_cassandra__schema__cql_type('address') is_expected.to contain_exec('/usr/bin/cqlsh -e "DROP type Excalibur.address" localhost 9042') end end context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'latest' } end it { is_expected.to raise_error(Puppet::Error) } end end diff --git a/spec/defines/schema/index_spec.rb b/spec/defines/schema/index_spec.rb index f45d716..de26cd9 100644 --- a/spec/defines/schema/index_spec.rb +++ b/spec/defines/schema/index_spec.rb @@ -1,121 +1,129 @@ require 'spec_helper' describe 'cassandra::schema::index' do context 'Create a basic index' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'user_index' } let(:params) do { keys: 'lname', keyspace: 'mykeyspace', - table: 'users' + table: 'users', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to compile is_expected.to contain_cassandra__schema__index('user_index') is_expected.to contain_exec('/usr/bin/cqlsh -e "CREATE INDEX IF NOT EXISTS user_index ON mykeyspace.users (lname)" localhost 9042') end end context 'Create a custom index.' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'user_index' } let(:params) do { class_name: 'path.to.the.IndexClass', keys: 'email', keyspace: 'Excelsior', - table: 'users' + table: 'users', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to compile is_expected.to contain_exec('/usr/bin/cqlsh -e "CREATE CUSTOM INDEX IF NOT EXISTS user_index ON Excelsior.users (email) USING \'path.to.the.IndexClass\'" localhost 9042') end end context 'Create a custom index with options.' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'user_index' } let(:params) do { class_name: 'path.to.the.IndexClass', keys: 'email', keyspace: 'Excelsior', options: "{'storage': '/mnt/ssd/indexes/'}", - table: 'users' + table: 'users', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to compile is_expected.to contain_exec('/usr/bin/cqlsh -e "CREATE CUSTOM INDEX IF NOT EXISTS user_index ON Excelsior.users (email) USING \'path.to.the.IndexClass\' WITH OPTIONS = {\'storage\': \'/mnt/ssd/indexes/\'}" localhost 9042') end end context 'Drop Index' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'user_index' } let(:params) do { ensure: 'absent', keys: 'lname', keyspace: 'Excelsior', - table: 'users' + table: 'users', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to compile is_expected.to contain_exec('/usr/bin/cqlsh -e "DROP INDEX Excelsior.user_index" localhost 9042') end end context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'latest' } end it { is_expected.to raise_error(Puppet::Error) } end end diff --git a/spec/defines/schema/keyspace_spec.rb b/spec/defines/schema/keyspace_spec.rb index 25b9213..83130d3 100644 --- a/spec/defines/schema/keyspace_spec.rb +++ b/spec/defines/schema/keyspace_spec.rb @@ -1,99 +1,105 @@ require 'spec_helper' describe 'cassandra::schema::keyspace' do context 'Set ensure to present (SimpleStrategy)' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'present', replication_map: { 'keyspace_class' => 'SimpleStrategy', 'replication_factor' => 3 - } + }, + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to compile is_expected.to contain_class('cassandra::schema') is_expected.to contain_exec('/usr/bin/cqlsh -e "CREATE KEYSPACE IF NOT EXISTS foobar WITH REPLICATION = { \'class\' : \'SimpleStrategy\', \'replication_factor\' : 3 } AND DURABLE_WRITES = true" localhost 9042') end end context 'Set ensure to present (NetworkTopologyStrategy)' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'present', replication_map: { 'keyspace_class' => 'NetworkTopologyStrategy', 'dc1' => '3', 'dc2' => '2' - } + }, + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to contain_cassandra__schema__keyspace('foobar') is_expected.to contain_exec('/usr/bin/cqlsh -e "CREATE KEYSPACE IF NOT EXISTS foobar WITH REPLICATION = { \'class\' : \'NetworkTopologyStrategy\', \'dc1\': 3, \'dc2\': 2 } AND DURABLE_WRITES = true" localhost 9042') end end context 'Set ensure to absent' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { - ensure: 'absent' + ensure: 'absent', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to compile is_expected.to contain_exec('/usr/bin/cqlsh -e "DROP KEYSPACE foobar" localhost 9042') end end context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'latest' } end it { is_expected.to raise_error(Puppet::Error) } end end diff --git a/spec/defines/schema/permission_spec.rb b/spec/defines/schema/permission_spec.rb index 7bd53c8..96022f4 100644 --- a/spec/defines/schema/permission_spec.rb +++ b/spec/defines/schema/permission_spec.rb @@ -1,174 +1,184 @@ require 'spec_helper' describe 'cassandra::schema::permission' do context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { user_name: 'foobar' } end it { is_expected.to raise_error(Puppet::Error) } end context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'latest' } end it { is_expected.to raise_error(Puppet::Error) } end context 'spillman:SELECT:ALL' do let(:title) { 'spillman:SELECT:ALL' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'spillman', - permission_name: 'SELECT' + permission_name: 'SELECT', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('spillman:SELECT:ALL') is_expected.to contain_exec('GRANT SELECT ON ALL KEYSPACES TO spillman') end end context 'akers:modify:field' do let(:title) { 'akers:modify:field' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'akers', keyspace_name: 'field', - permission_name: 'MODIFY' + permission_name: 'MODIFY', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('akers:modify:field') is_expected.to contain_exec('GRANT MODIFY ON KEYSPACE field TO akers') end end context 'boone:alter:forty9ers' do let(:title) { 'boone:alter:forty9ers' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'boone', keyspace_name: 'forty9ers', - permission_name: 'ALTER' + permission_name: 'ALTER', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('boone:alter:forty9ers') is_expected.to contain_exec('GRANT ALTER ON KEYSPACE forty9ers TO boone') end end context 'boone:ALL:ravens.plays' do let(:title) { 'boone:ALL:ravens.plays' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'boone', keyspace_name: 'ravens', - table_name: 'plays' + table_name: 'plays', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to have_resource_count(18) is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays') is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays - ALTER').with( ensure: 'present', user_name: 'boone', keyspace_name: 'ravens', permission_name: 'ALTER', table_name: 'plays' ) is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays - AUTHORIZE') is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays - DROP') is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays - MODIFY') is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays - SELECT') is_expected.to contain_exec('GRANT ALTER ON TABLE ravens.plays TO boone') is_expected.to contain_exec('GRANT AUTHORIZE ON TABLE ravens.plays TO boone') is_expected.to contain_exec('GRANT DROP ON TABLE ravens.plays TO boone') is_expected.to contain_exec('GRANT MODIFY ON TABLE ravens.plays TO boone') is_expected.to contain_exec('GRANT SELECT ON TABLE ravens.plays TO boone') end end context 'REVOKE boone:SELECT:ravens.plays' do let(:title) { 'REVOKE boone:SELECT:ravens.plays' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { ensure: 'absent', user_name: 'boone', keyspace_name: 'forty9ers', - permission_name: 'SELECT' + permission_name: 'SELECT', + use_scl: false, + scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('REVOKE boone:SELECT:ravens.plays') is_expected.to contain_exec('REVOKE SELECT ON KEYSPACE forty9ers FROM boone') end end end diff --git a/spec/defines/schema/table_spec.rb b/spec/defines/schema/table_spec.rb index 73d15da..0efcadb 100644 --- a/spec/defines/schema/table_spec.rb +++ b/spec/defines/schema/table_spec.rb @@ -1,82 +1,86 @@ require 'spec_helper' describe 'cassandra::schema::table' do context 'Create Table' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'users' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', keyspace: 'Excelsior', columns: { 'userid' => 'text', 'username' => 'FROZEN', 'emails' => 'set', 'top_scores' => 'list', 'todo' => 'map', 'COLLECTION-TYPE' => 'tuple', 'PRIMARY KEY' => '(userid)' }, options: [ 'COMPACT STORAGE', 'ID=\'5a1c395e-b41f-11e5-9f22-ba0be0483c18\'' ] } end it do is_expected.to compile is_expected.to contain_cassandra__schema__table('users') is_expected.to contain_exec('/usr/bin/cqlsh -e "CREATE TABLE IF NOT EXISTS Excelsior.users (userid text, username FROZEN, emails set, top_scores list, todo map, tuple, PRIMARY KEY (userid)) WITH COMPACT STORAGE AND ID=\'5a1c395e-b41f-11e5-9f22-ba0be0483c18\'" localhost 9042') end end context 'Drop Table' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'users' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', keyspace: 'Excelsior', ensure: 'absent' } end it do is_expected.to compile is_expected.to contain_exec('/usr/bin/cqlsh -e "DROP TABLE IF EXISTS Excelsior.users" localhost 9042') end end context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'latest' } end it { is_expected.to raise_error(Puppet::Error) } end end diff --git a/spec/defines/schema/user_spec.rb b/spec/defines/schema/user_spec.rb index 9c7af1b..f149860 100644 --- a/spec/defines/schema/user_spec.rb +++ b/spec/defines/schema/user_spec.rb @@ -1,200 +1,214 @@ require 'spec_helper' describe 'cassandra::schema::user' do context 'Create a supper user on cassandrarelease undef' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat', cassandrarelease: nil } end let(:title) { 'akers' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', password: 'Niner2', superuser: true } end it do is_expected.to contain_cassandra__schema__user('akers').with_ensure('present') is_expected.to contain_exec('Create user (akers)').with( command: '/usr/bin/cqlsh -e "CREATE USER IF NOT EXISTS akers WITH PASSWORD \'Niner2\' SUPERUSER" localhost 9042' ) end end context 'Create a supper user in cassandrarelease < 2.2' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat', cassandrarelease: '2.0.1' } end let(:title) { 'akers' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', password: 'Niner2', superuser: true } end it do is_expected.to contain_cassandra__schema__user('akers').with_ensure('present') is_expected.to contain_exec('Create user (akers)').with( command: '/usr/bin/cqlsh -e "CREATE USER IF NOT EXISTS akers WITH PASSWORD \'Niner2\' SUPERUSER" localhost 9042' ) end end context 'Create a user in cassandrarelease < 2.2' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat', cassandrarelease: '2.0.1' } end let(:title) { 'akers' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', password: 'Niner2' } end it do is_expected.to contain_cassandra__schema__user('akers').with_ensure('present') is_expected.to contain_exec('Create user (akers)').with( command: '/usr/bin/cqlsh -e "CREATE USER IF NOT EXISTS akers WITH PASSWORD \'Niner2\' NOSUPERUSER" localhost 9042' ) end end context 'Create a supper user with login in cassandrarelease > 2.2' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat', cassandrarelease: '3.0.9' } end let(:title) { 'akers' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', password: 'Niner2', superuser: true } end it do is_expected.to contain_cassandra__schema__user('akers').with_ensure('present') is_expected.to contain_exec('Create user (akers)').with( command: '/usr/bin/cqlsh -e "CREATE ROLE IF NOT EXISTS akers WITH PASSWORD = \'Niner2\' AND SUPERUSER = true AND LOGIN = true" localhost 9042' ) end end context 'Create a user without login in cassandrarelease > 2.2' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat', cassandrarelease: '3.0.9' } end let(:title) { 'bob' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', password: 'kaZe89a', login: false } end it do is_expected.to contain_cassandra__schema__user('bob').with_ensure('present') is_expected.to contain_exec('Create user (bob)').with( command: '/usr/bin/cqlsh -e "CREATE ROLE IF NOT EXISTS bob WITH PASSWORD = \'kaZe89a\'" localhost 9042' ) end end context 'Drop a user in cassandrarelease > 2.2' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat', cassandrarelease: '3.0.9' } end let(:title) { 'akers' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', password: 'Niner2', ensure: 'absent' } end it do is_expected.to contain_exec('Delete user (akers)').with( command: '/usr/bin/cqlsh -e "DROP ROLE akers" localhost 9042' ) end end context 'Drop a user in cassandrarelease < 2.2' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat', cassandrarelease: '2.0.2' } end let(:title) { 'akers' } let(:params) do { + use_scl: false, + scl_name: 'nodefault', password: 'Niner2', ensure: 'absent' } end it do is_expected.to contain_exec('Delete user (akers)').with( command: '/usr/bin/cqlsh -e "DROP USER akers" localhost 9042' ) end end context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'latest' } end it { is_expected.to raise_error(Puppet::Error) } end end