multi_index 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +18 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +190 -0
- data/Rakefile +1 -0
- data/bin/multi-index +8 -0
- data/lib/multi_index/commands.rb +114 -0
- data/lib/multi_index/common.rb +44 -0
- data/lib/multi_index/encryption.rb +28 -0
- data/lib/multi_index/google_doc.rb +90 -0
- data/lib/multi_index/validation.rb +93 -0
- data/lib/multi_index/version.rb +3 -0
- data/multi_index.gemspec +30 -0
- data/test.rb +4 -0
- metadata +186 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NjY5YWU3OGU5YzA2N2EyY2E5Zjg4NTUzYTQ3ZDc2Y2RkOTQ1ZjUyNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NDMxNzZmMzRiNzdiY2VhN2FjMjk1MzQ0NTYzYTM4ZWY0MjA3OTZhYQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZTlmNmFiNmNhMmE0NDU0ZjUyOTI4YWRjZDEyYzA1MmJiZjZjMWUxOTFhNjk5
|
10
|
+
ZDNjMGQ4M2Q3MDNiNDAxMGMyMjk3YzYzZDdlYzZhOWI5YzMzZTQxZDIyYzVk
|
11
|
+
NmNmYmZkYWE1ZWQ1NjBlZmJmM2U1NzY5Yjc2ZDkyZDExYWVhMGU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NWVjNDk0NzM0Mzk0Y2VkNDAyNzU0YmU2ZWRjMTMyYmQ4ODFkMWY0MWVhYWMz
|
14
|
+
NjJiZjFjNjMwNmRhNjM1OTkxNDQ4MGVjYTMwZjdjZTE1NWViMWMzM2YzMDBm
|
15
|
+
N2ZjMjE1NzI5M2Y5ZjljYjNjMmQxMzEzMDQyYzU1NWE4MGM0Y2Q=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Nayyara Samuel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
# MultiIndex
|
2
|
+
|
3
|
+
Gem reads an Excel Google Doc containing the multi-index mapping used in the Segmentation system and writes results to output or updates EAS or Config Service with the desired configuration.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'multi_index'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install multi_index
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
This gem comes with a command interface. Once installed the `multi-index` executable should be on your path. To get help run the command:
|
22
|
+
|
23
|
+
```
|
24
|
+
multi-index config [SUBCOMMAND] -t, --tier=TIER # Command to retrieve configuration by tier
|
25
|
+
multi-index help [COMMAND] # Describe available commands or one specific command
|
26
|
+
```
|
27
|
+
|
28
|
+
The main command here is config. To retrieve help type `multi-index help config` (this will show you all options available whereas the example above only shows required options):
|
29
|
+
|
30
|
+
```
|
31
|
+
Usage:
|
32
|
+
multi-index config [SUBCOMMAND] -t, --tier=TIER
|
33
|
+
|
34
|
+
Options:
|
35
|
+
-t, --tier=TIER # The tier of the configuration. Use ALL to get all tiers.
|
36
|
+
# Default: ALL
|
37
|
+
-p, [--profile=PROFILE] # The profile yaml file for logging into Google Drive and LDAP and key of the Google doc to read from.
|
38
|
+
|
39
|
+
Command to retrieve configuration by tier
|
40
|
+
```
|
41
|
+
|
42
|
+
### Subcommands and Getting Help
|
43
|
+
The gem currently only writes to *STDOUT*. Writing to local EAS codebase and Config Service is not available yet.
|
44
|
+
|
45
|
+
To get help about subcommand run `multi-index config help`:
|
46
|
+
|
47
|
+
```
|
48
|
+
multi-index config help [COMMAND] # Describe subcommands or one specific subcommand
|
49
|
+
multi-index config write # Write config to a target.
|
50
|
+
```
|
51
|
+
|
52
|
+
The write subcommand in available. To get help on this command run `multi-index config help write`:
|
53
|
+
|
54
|
+
```
|
55
|
+
Usage:
|
56
|
+
multi-index write
|
57
|
+
|
58
|
+
Options:
|
59
|
+
-o, [--output=OUTPUT] # The destination to write configuration output to. Allowed: ["EAS", "CONFIG_SERVICE", "stdout"]
|
60
|
+
# Default: stdout
|
61
|
+
-f, [--format=FORMAT] # The format of output. Depending on output might be inferred automatically. Allowed: ["yaml", "json", "escaped"]
|
62
|
+
# Default: yaml
|
63
|
+
-i, [--invert] # Invert from alias-indices to index-alias map
|
64
|
+
|
65
|
+
Write config to a target.
|
66
|
+
```
|
67
|
+
### Example Profile File
|
68
|
+
|
69
|
+
A profile file will have sensitive information encrypted (such as passwords). This can be generated for example by running the command `multi-index config profile -f profile.yml`. This command will prompt you for the fields and then write the data to a profile file for future use, so you don't need to type in your credential everytime.
|
70
|
+
|
71
|
+
```
|
72
|
+
google_drive:
|
73
|
+
email: nayyara.samuel@opower.com
|
74
|
+
password: OpripQ+sdkf78==
|
75
|
+
key: 0AjHO2wGDCPKcdEF0bWgxV1VvQUx1NzNic2VxWWlNQ1E
|
76
|
+
sheet: 0
|
77
|
+
|
78
|
+
```
|
79
|
+
|
80
|
+
### Examples of Runs with Parameters
|
81
|
+
|
82
|
+
**COMMAND:** `multi-index config -t dev -p profile.yml write -o stdout -f json -i`
|
83
|
+
|
84
|
+
```
|
85
|
+
******** MULTI-INDEX CONFIGURATION: dev ********
|
86
|
+
{
|
87
|
+
"dev": {
|
88
|
+
"cpau": "segmentation-entity-attributes-qa-1",
|
89
|
+
"dir": "segmentation-entity-attributes-qa-1",
|
90
|
+
"otp": "segmentation-entity-attributes-qa-1",
|
91
|
+
"wmco": "segmentation-entity-attributes-qa-1",
|
92
|
+
"demo": "segmentation-entity-attributes-qa-1",
|
93
|
+
"cec": "segmentation-entity-attributes-qa-1",
|
94
|
+
"ngma": "segmentation-entity-attributes-qa-1",
|
95
|
+
"pge": "segmentation-entity-attributes-qa-1",
|
96
|
+
"aepo": "segmentation-entity-attributes-qa-1"
|
97
|
+
}
|
98
|
+
}
|
99
|
+
```
|
100
|
+
|
101
|
+
**COMMAND:** `multi-index config -t ALL -p profile.yml write -o stdout -f yaml`
|
102
|
+
|
103
|
+
```
|
104
|
+
******** MULTI-INDEX CONFIGURATION: ALL ********`
|
105
|
+
---
|
106
|
+
dev:
|
107
|
+
segmentation-entity-attributes-qa-1:
|
108
|
+
- cpau
|
109
|
+
- dir
|
110
|
+
- otp
|
111
|
+
- wmco
|
112
|
+
- demo
|
113
|
+
- cec
|
114
|
+
- ngma
|
115
|
+
- pge
|
116
|
+
- aepo
|
117
|
+
stage:
|
118
|
+
segmentation-entity-attributes-stage-1:
|
119
|
+
- cpau
|
120
|
+
- dir
|
121
|
+
- otp
|
122
|
+
- wmco
|
123
|
+
- demo
|
124
|
+
- cec
|
125
|
+
- ngma
|
126
|
+
- pge
|
127
|
+
- aepo
|
128
|
+
prod:
|
129
|
+
segmentation-entity-attribute-production-1:
|
130
|
+
- cpau
|
131
|
+
- dir
|
132
|
+
- otp
|
133
|
+
- wmco
|
134
|
+
- demo
|
135
|
+
- cec
|
136
|
+
- ngma
|
137
|
+
- pge
|
138
|
+
- aepo
|
139
|
+
|
140
|
+
```
|
141
|
+
|
142
|
+
**COMMAND:** `multi-index config -t ALL -p profile.yml write -o stdout -f yaml -i`
|
143
|
+
|
144
|
+
```
|
145
|
+
_api
|
146
|
+
******** MULTI-INDEX CONFIGURATION: ALL ********
|
147
|
+
---
|
148
|
+
dev:
|
149
|
+
cpau: segmentation-entity-attributes-qa-1
|
150
|
+
dir: segmentation-entity-attributes-qa-1
|
151
|
+
otp: segmentation-entity-attributes-qa-1
|
152
|
+
wmco: segmentation-entity-attributes-qa-1
|
153
|
+
demo: segmentation-entity-attributes-qa-1
|
154
|
+
cec: segmentation-entity-attributes-qa-1
|
155
|
+
ngma: segmentation-entity-attributes-qa-1
|
156
|
+
pge: segmentation-entity-attributes-qa-1
|
157
|
+
aepo: segmentation-entity-attributes-qa-1
|
158
|
+
stage:
|
159
|
+
cpau: segmentation-entity-attributes-stage-1
|
160
|
+
dir: segmentation-entity-attributes-stage-1
|
161
|
+
otp: segmentation-entity-attributes-stage-1
|
162
|
+
wmco: segmentation-entity-attributes-stage-1
|
163
|
+
demo: segmentation-entity-attributes-stage-1
|
164
|
+
cec: segmentation-entity-attributes-stage-1
|
165
|
+
ngma: segmentation-entity-attributes-stage-1
|
166
|
+
pge: segmentation-entity-attributes-stage-1
|
167
|
+
aepo: segmentation-entity-attributes-stage-1
|
168
|
+
prod:
|
169
|
+
cpau: segmentation-entity-attribute-production-1
|
170
|
+
dir: segmentation-entity-attribute-production-1
|
171
|
+
otp: segmentation-entity-attribute-production-1
|
172
|
+
wmco: segmentation-entity-attribute-production-1
|
173
|
+
demo: segmentation-entity-attribute-production-1
|
174
|
+
cec: segmentation-entity-attribute-production-1
|
175
|
+
ngma: segmentation-entity-attribute-production-1
|
176
|
+
pge: segmentation-entity-attribute-production-1
|
177
|
+
aepo: segmentation-entity-attribute-production-1
|
178
|
+
```
|
179
|
+
|
180
|
+
## TODO
|
181
|
+
- Allow user to push to Config Service
|
182
|
+
|
183
|
+
|
184
|
+
## Contributing
|
185
|
+
|
186
|
+
1. Fork it ( http://github.com/<my-github-username>/multi_index/fork )
|
187
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
188
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
189
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
190
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/multi-index
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'validation'
|
3
|
+
require 'thor'
|
4
|
+
require 'google_doc'
|
5
|
+
require 'colorize'
|
6
|
+
require 'prettify'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
#
|
10
|
+
# Command related to retrieving config.
|
11
|
+
# Author: Nayyara Samuel (nayyara.samuel@opower.com)
|
12
|
+
#
|
13
|
+
|
14
|
+
# Subcommands for config
|
15
|
+
module MultiIndex
|
16
|
+
class Config < Thor
|
17
|
+
include Preconditions
|
18
|
+
include MultiIndex::CommandsCommon
|
19
|
+
include MultiIndex::ConfigValidation
|
20
|
+
include Prettify::Prettifier
|
21
|
+
|
22
|
+
desc 'write', 'Write config to a target.'
|
23
|
+
option :output, type: :string, aliases: '-o', default: 'stdout', desc: "The destination to write configuration output to. Allowed: #{ALLOWED_VALUES[:output]}"
|
24
|
+
option :format, type: :string, aliases: '-f', default: 'yaml', desc: "The format of output. Depending on output might be inferred automatically. Allowed: #{ALLOWED_VALUES[:format]}"
|
25
|
+
option :invert, type: :boolean, aliases: '-i', default: false, desc: 'Invert from alias-indices to index-alias map'
|
26
|
+
|
27
|
+
def write
|
28
|
+
with_exception_handling do
|
29
|
+
print_parameters(options)
|
30
|
+
|
31
|
+
write_options = validate_write_parameters(options)
|
32
|
+
config_options = validate_config_parameters(options)
|
33
|
+
profile = config_options[:profile]
|
34
|
+
tier = config_options[:tier]
|
35
|
+
|
36
|
+
mapping = MultiIndex::GoogleDoc.new(profile[:google_drive]).mapping
|
37
|
+
output = write_options[:output]
|
38
|
+
format = write_options[:format]
|
39
|
+
method = options['invert'] || (output != 'stdout') ? :invert : :original
|
40
|
+
|
41
|
+
case output
|
42
|
+
|
43
|
+
when 'stdout'
|
44
|
+
puts "******** MULTI-INDEX CONFIGURATION: #{tier} ********".green
|
45
|
+
case format
|
46
|
+
when 'yaml'
|
47
|
+
puts mapping.send(method, tier).to_yaml.green
|
48
|
+
when 'json'
|
49
|
+
puts prettify(mapping.send(method, tier).to_json).green
|
50
|
+
when 'escaped'
|
51
|
+
puts prettify(mapping.send(method, tier).to_json).gsub(',', '\,').green
|
52
|
+
end
|
53
|
+
break
|
54
|
+
|
55
|
+
when 'EAS'
|
56
|
+
LOG.info 'Performing update assuming present working directory is EAS'
|
57
|
+
resources_path = 'entity-attribute-server/src/main/resources'
|
58
|
+
|
59
|
+
mapping.send(method, tier).each do |tier, indices|
|
60
|
+
indices = Hash[indices.map { |k, v| [k.upcase, v] }]
|
61
|
+
config_filename = "#{resources_path}/#{tier}.yml"
|
62
|
+
|
63
|
+
config = YAML.load_file(config_filename)
|
64
|
+
LOG.info "Updating file: #{config_filename} for tier: #{tier}"
|
65
|
+
config['elasticsearch'] ||= {}
|
66
|
+
config['elasticsearch'].merge!({'indices' => indices})
|
67
|
+
|
68
|
+
config_file = File.open(config_filename, 'w')
|
69
|
+
config_file.write(config.to_yaml.gsub(/^---\n/, ''))
|
70
|
+
config_file.close
|
71
|
+
end
|
72
|
+
break
|
73
|
+
|
74
|
+
else
|
75
|
+
# TODO: Code for config service writing
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
desc 'profile', 'Create a profile for logging into Google Drive/LDAP and accessing Google Doc with mapping'
|
81
|
+
option :file, type: :string, aliases: '-f', required: true, desc: 'The path of the file to write profile to'
|
82
|
+
|
83
|
+
def profile
|
84
|
+
with_exception_handling do
|
85
|
+
print_parameters(options)
|
86
|
+
|
87
|
+
filename = options['file']
|
88
|
+
format = (/.+\.json$/.match(filename)) ? :to_json : ((/.+\.yml/.match(filename)) ? :to_yaml : :unknown)
|
89
|
+
check_argument(format != :unknown, 'File must end with a .json or .yml extension')
|
90
|
+
|
91
|
+
# Reuse validation code so there is no duplication
|
92
|
+
# Set output to CONFIG_SERVICE to force LDAP prompts
|
93
|
+
profile = validate_config_parameters({'output' => 'CONFIG_SERVICE'})[:profile]
|
94
|
+
file = File.open(filename, 'w')
|
95
|
+
file.write(profile.send(format))
|
96
|
+
file.close
|
97
|
+
|
98
|
+
LOG.info "Profile written to #{filename}. You can now use this file with the -p option in the `write` command."
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Parent `config` command
|
106
|
+
class Commands < Thor
|
107
|
+
|
108
|
+
desc 'config [SUBCOMMAND]', 'Command to retrieve configuration by tier'
|
109
|
+
option :tier, type: :string, aliases: '-t', required: true, default: 'ALL', desc: 'The tier of the configuration. Use ALL to get all tiers.'
|
110
|
+
option :profile, type: :string, aliases: '-p', desc: 'The profile yaml file for logging into Google Drive and/or LDAP and key of the Google doc to read from.'
|
111
|
+
|
112
|
+
subcommand 'config', MultiIndex::Config
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'preconditions'
|
2
|
+
require 'logging_factory'
|
3
|
+
require 'colorize'
|
4
|
+
#
|
5
|
+
# Contains common code used by Thor commands.
|
6
|
+
# Author: Nayyara Samuel (nayyara.samuel@opower.com)
|
7
|
+
#
|
8
|
+
module MultiIndex
|
9
|
+
module CommandsCommon
|
10
|
+
LOG = Opower::LOGGING_FACTORY.log('MultiIndex')
|
11
|
+
|
12
|
+
def with_exception_handling(&block)
|
13
|
+
begin
|
14
|
+
yield
|
15
|
+
rescue Exception => ex
|
16
|
+
LOG.fatal "Something went wrong: \n #{ex.message} \n #{ex.backtrace.join("\n")}\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_parameters(options, groups={})
|
21
|
+
puts "\nRunning with parameters:".bold
|
22
|
+
|
23
|
+
options.keys.each do |k|
|
24
|
+
puts "\t#{k}: #{options[k]}".yellow
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# To make methods on these modules available
|
32
|
+
module Preconditions
|
33
|
+
def self.included(receiver)
|
34
|
+
receiver.send :include, PreconditionMixinMethods
|
35
|
+
receiver.send :include, PreconditionModuleClassMethods
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# To enable bold fonts in the terminal
|
40
|
+
class String
|
41
|
+
def bold;
|
42
|
+
"\033[1m#{self}\033[22m"
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'encryptor'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Module for encryption and decryption
|
6
|
+
# Author: Nayyara Samuel (nayyara.samuel@opower.com)
|
7
|
+
#
|
8
|
+
|
9
|
+
module MultiIndex
|
10
|
+
module Encryption
|
11
|
+
|
12
|
+
def secret_key
|
13
|
+
'PLrijCx6/ZD3ET6im5OI7A='
|
14
|
+
end
|
15
|
+
|
16
|
+
def encrypt(text)
|
17
|
+
Base64.encode64(Encryptor.encrypt(text.strip,
|
18
|
+
:key => secret_key,
|
19
|
+
:algorithm => 'aes-256-ecb')).force_encoding('UTF-8').strip
|
20
|
+
end
|
21
|
+
|
22
|
+
def decrypt(text)
|
23
|
+
Encryptor.decrypt(Base64.decode64(text.force_encoding('ASCII-8BIT')),
|
24
|
+
:key => secret_key,
|
25
|
+
:algorithm => 'aes-256-ecb').strip
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'google_drive'
|
2
|
+
require 'common'
|
3
|
+
require 'encryption'
|
4
|
+
|
5
|
+
#
|
6
|
+
# Class for reading a Google doc spreadsheet data
|
7
|
+
# Author: Nayyara Samuel (nayyara.samuel@opower.com)
|
8
|
+
#
|
9
|
+
|
10
|
+
module MultiIndex
|
11
|
+
class Mapping
|
12
|
+
|
13
|
+
def initialize(content)
|
14
|
+
@content = content
|
15
|
+
end
|
16
|
+
|
17
|
+
def original(tier)
|
18
|
+
tier_specific(tier)
|
19
|
+
end
|
20
|
+
|
21
|
+
def invert(tier)
|
22
|
+
start = tier_specific(tier)
|
23
|
+
start.reduce({}) do |result, (tier, mapping)|
|
24
|
+
indices_to_alias = Hash[mapping.invert.map do |indices, _alias|
|
25
|
+
indices.map { |index| [index, _alias] }
|
26
|
+
end.first]
|
27
|
+
result[tier] = indices_to_alias
|
28
|
+
result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def tier_specific(tier)
|
34
|
+
(tier == 'ALL') ? @content : ({tier => @content[tier]})
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class GoogleDoc
|
39
|
+
include Encryption
|
40
|
+
include Preconditions
|
41
|
+
include CommandsCommon
|
42
|
+
|
43
|
+
attr_reader :mapping
|
44
|
+
|
45
|
+
def initialize(profile)
|
46
|
+
LOG.info "Using Google Drive parameters: \n #{profile.to_hash.to_yaml}"
|
47
|
+
session = GoogleDrive.login(profile[:email], decrypt(profile[:password]))
|
48
|
+
worksheet = session.spreadsheet_by_key(profile[:key])
|
49
|
+
LOG.info("Using worksheet: #{worksheet.human_url}")
|
50
|
+
|
51
|
+
cell_contents = worksheet.export_as_string('csv').split("\n").map { |row| row.split(',') }
|
52
|
+
|
53
|
+
#Check structure of document to ensure it matches expected format
|
54
|
+
check_argument(cell_contents.size >= 2, 'Worksheet must have at least 2 rows')
|
55
|
+
tier_row = cell_contents.shift
|
56
|
+
check_argument(tier_row.first == 'tier', 'First row must begin with a `tier` cell')
|
57
|
+
index_row = cell_contents.shift
|
58
|
+
check_argument(index_row[0] == 'index', 'Second row must begin with a `index` cell')
|
59
|
+
|
60
|
+
@mapping = Mapping.new(parse(tier_row, index_row, cell_contents))
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def parse(tier_row, index_row, cell_contents)
|
65
|
+
tier_keys = tier_row[1..tier_row.size]
|
66
|
+
|
67
|
+
result = tier_keys.reduce({}) do |hash, tier|
|
68
|
+
hash[tier] = {}
|
69
|
+
hash
|
70
|
+
end
|
71
|
+
|
72
|
+
cell_contents.each do |content_row|
|
73
|
+
is_index_name_row = !content_row.first.empty? && content_row.first == 'index'
|
74
|
+
values = content_row[1..content_row.size]
|
75
|
+
if is_index_name_row
|
76
|
+
index_row = content_row
|
77
|
+
else
|
78
|
+
(0...tier_keys.size).each do |tier|
|
79
|
+
if values[tier]
|
80
|
+
result[tier_keys[tier]][index_row[tier + 1]] ||= []
|
81
|
+
result[tier_keys[tier]][index_row[tier + 1]] << values[tier]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
result
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'encryption'
|
3
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
4
|
+
|
5
|
+
#
|
6
|
+
# Validation for inputs of config command.
|
7
|
+
# Author: Nayyara Samuel (nayyara.samuel@opower.com)
|
8
|
+
#
|
9
|
+
module MultiIndex
|
10
|
+
module ConfigValidation
|
11
|
+
include MultiIndex::CommandsCommon
|
12
|
+
include MultiIndex::Encryption
|
13
|
+
|
14
|
+
ALLOWED_VALUES = {
|
15
|
+
output: ['EAS', 'CONFIG_SERVICE', 'stdout'],
|
16
|
+
format: ['yaml', 'json', 'escaped']
|
17
|
+
}
|
18
|
+
MAPPING_FORMAT = {
|
19
|
+
'EAS' => 'yaml',
|
20
|
+
'CONFIG_SERVICE' => 'escaped'
|
21
|
+
}
|
22
|
+
|
23
|
+
def validate_write_parameters(options)
|
24
|
+
output, format = options['output'], options['format']
|
25
|
+
|
26
|
+
#Check preconditions
|
27
|
+
check_argument(ALLOWED_VALUES[:output].include?(output), "Output must be one of #{ALLOWED_VALUES[:output]}")
|
28
|
+
|
29
|
+
if (MAPPING_FORMAT[output])
|
30
|
+
format = MAPPING_FORMAT[output]
|
31
|
+
LOG.info "Format is automatically set to #{format} for #{output}"
|
32
|
+
end
|
33
|
+
|
34
|
+
check_argument(ALLOWED_VALUES[:format].include?(format), "Format must be one of #{ALLOWED_VALUES[:format]}")
|
35
|
+
|
36
|
+
{
|
37
|
+
output: output,
|
38
|
+
format: format
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
begin
|
43
|
+
require 'io/console'
|
44
|
+
rescue LoadError
|
45
|
+
end
|
46
|
+
|
47
|
+
if STDIN.respond_to?(:noecho)
|
48
|
+
def get_password(prompt="Password: ")
|
49
|
+
print prompt
|
50
|
+
result = STDIN.noecho(&:gets).chomp
|
51
|
+
puts
|
52
|
+
result
|
53
|
+
end
|
54
|
+
else
|
55
|
+
def get_password(prompt="Password: ")
|
56
|
+
result = `read -s -p "#{prompt}" password; echo $password`.chomp
|
57
|
+
puts
|
58
|
+
result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_plain(prompt)
|
63
|
+
print prompt
|
64
|
+
STDIN.gets.chomp
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_config_parameters(options)
|
68
|
+
profile = options['profile']
|
69
|
+
profile = HashWithIndifferentAccess.new(YAML.load_file(profile)) if profile
|
70
|
+
|
71
|
+
profile ||= {
|
72
|
+
google_drive: {},
|
73
|
+
ldap: {}
|
74
|
+
}
|
75
|
+
|
76
|
+
LOG.info '*** Google Drive Credentials/Access Info ****'
|
77
|
+
profile[:google_drive][:email] ||= get_plain('Google Email: ')
|
78
|
+
profile[:google_drive][:password] ||= encrypt(get_password('Google password: '))
|
79
|
+
profile[:google_drive][:key] ||= get_plain('Document Key: ')
|
80
|
+
profile[:google_drive][:sheet] ||= get_plain('Sheet Index: ')
|
81
|
+
|
82
|
+
if (options['output'] == 'CONFIG_SERVICE' && profile[:ldap].empty?)
|
83
|
+
LOG.info '*** LDAP Credentials (for Config Service): ****'
|
84
|
+
profile[:ldap][:email] ||= get_plain('LDAP Username: ')
|
85
|
+
profile[:ldap][:password] ||= encrypt(get_password('LDAP Password: '))
|
86
|
+
profile[:ldap][:key] ||= get_plain('Config Key: ')
|
87
|
+
end
|
88
|
+
|
89
|
+
options.merge!({profile: profile})
|
90
|
+
options
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/multi_index.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'multi_index/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "multi_index"
|
8
|
+
spec.version = MultiIndex::VERSION
|
9
|
+
spec.authors = 'Nayyara Samuel'
|
10
|
+
spec.email = ['nayyara.samuel@gmail.com']
|
11
|
+
spec.summary = 'Read a multi-index configuration and return the desired configuration format'
|
12
|
+
spec.description = 'Use this gem to generate or update configurations'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib', 'lib/multi_index']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
|
23
|
+
spec.add_dependency 'google_drive', '~> 0.3.7'
|
24
|
+
spec.add_dependency 'thor'
|
25
|
+
spec.add_dependency 'preconditions'
|
26
|
+
spec.add_dependency 'logging_factory'
|
27
|
+
spec.add_dependency 'colorize'
|
28
|
+
spec.add_dependency 'encryptor'
|
29
|
+
spec.add_dependency 'prettify'
|
30
|
+
end
|
data/test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: multi_index
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nayyara Samuel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: google_drive
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.7
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.7
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: preconditions
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: logging_factory
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: colorize
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: encryptor
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: prettify
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Use this gem to generate or update configurations
|
140
|
+
email:
|
141
|
+
- nayyara.samuel@gmail.com
|
142
|
+
executables:
|
143
|
+
- multi-index
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- .gitignore
|
148
|
+
- Gemfile
|
149
|
+
- LICENSE.txt
|
150
|
+
- README.md
|
151
|
+
- Rakefile
|
152
|
+
- bin/multi-index
|
153
|
+
- lib/multi_index/commands.rb
|
154
|
+
- lib/multi_index/common.rb
|
155
|
+
- lib/multi_index/encryption.rb
|
156
|
+
- lib/multi_index/google_doc.rb
|
157
|
+
- lib/multi_index/validation.rb
|
158
|
+
- lib/multi_index/version.rb
|
159
|
+
- multi_index.gemspec
|
160
|
+
- test.rb
|
161
|
+
homepage:
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
metadata: {}
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
- lib/multi_index
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ! '>='
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ! '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubyforge_project:
|
182
|
+
rubygems_version: 2.2.2
|
183
|
+
signing_key:
|
184
|
+
specification_version: 4
|
185
|
+
summary: Read a multi-index configuration and return the desired configuration format
|
186
|
+
test_files: []
|