multi_index 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|