Class: Constancy::SyncTarget

Inherits:
Object
  • Object
show all
Defined in:
lib/constancy/sync_target.rb

Constant Summary collapse

VALID_CONFIG_KEYS =
%w( name type datacenter prefix path exclude chomp delete erb_enabled )
REQUIRED_CONFIG_KEYS =
%w( prefix )
VALID_TYPES =
[ :dir, :file ]
DEFAULT_TYPE =
:dir

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config:, consul_url:, token_source:, base_dir:, call_external_apis: true) ⇒ SyncTarget

Returns a new instance of SyncTarget.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/constancy/sync_target.rb', line 12

def initialize(config:, consul_url:, token_source:, base_dir:, call_external_apis: true)
  if not config.is_a? Hash
    raise Constancy::ConfigFileInvalid.new("Sync target entries must be specified as hashes")
  end

  if (config.keys - Constancy::SyncTarget::VALID_CONFIG_KEYS) != []
    raise Constancy::ConfigFileInvalid.new("Only the following keys are valid in a sync target entry: #{Constancy::SyncTarget::VALID_CONFIG_KEYS.join(", ")}")
  end

  if (Constancy::SyncTarget::REQUIRED_CONFIG_KEYS - config.keys) != []
    raise Constancy::ConfigFileInvalid.new("The following keys are required in a sync target entry: #{Constancy::SyncTarget::REQUIRED_CONFIG_KEYS.join(", ")}")
  end

  @base_dir = base_dir
  self.datacenter = config['datacenter']
  self.prefix = config['prefix']
  self.path = config['path'] || config['prefix']
  self.name = config['name']
  self.type = (config['type'] || Constancy::SyncTarget::DEFAULT_TYPE).to_sym
  unless Constancy::SyncTarget::VALID_TYPES.include?(self.type)
    raise Constancy::ConfigFileInvalid.new("Sync target '#{self.name || self.path}' has type '#{self.type}'. But only the following types are valid: #{Constancy::SyncTarget::VALID_TYPES.collect(&:to_s).join(", ")}")
  end

  if self.type == :file and File.directory?(self.base_path)
    raise Constancy::ConfigFileInvalid.new("Sync target '#{self.name || self.path}' has type 'file', but path '#{self.path}' is a directory.")
  end

  self.exclude = config['exclude'] || []
  if config.has_key?('chomp')
    @do_chomp = config['chomp'] ? true : false
  end
  if config.has_key?('delete')
    @do_delete = config['delete'] ? true : false
  else
    @do_delete = false
  end

  self.call_external_apis = call_external_apis
  self.consul_url = consul_url
  self.token_source = token_source
  token = if self.call_external_apis
            self.token_source.consul_token
          else
            ""
          end
  self.consul = Imperium::KV.new(Imperium::Configuration.new(url: self.consul_url, token: token))
  self.erb_enabled = config['erb_enabled']
end

Instance Attribute Details

#call_external_apisObject

Returns the value of attribute call_external_apis.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def call_external_apis
  @call_external_apis
end

#consulObject

Returns the value of attribute consul.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def consul
  @consul
end

#consul_urlObject

Returns the value of attribute consul_url.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def consul_url
  @consul_url
end

#datacenterObject

Returns the value of attribute datacenter.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def datacenter
  @datacenter
end

#erb_enabledObject

Returns the value of attribute erb_enabled.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def erb_enabled
  @erb_enabled
end

#excludeObject

Returns the value of attribute exclude.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def exclude
  @exclude
end

#nameObject

Returns the value of attribute name.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def name
  @name
end

#pathObject

Returns the value of attribute path.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def path
  @path
end

#prefixObject

Returns the value of attribute prefix.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def prefix
  @prefix
end

#token_sourceObject

Returns the value of attribute token_source.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def token_source
  @token_source
end

#typeObject

Returns the value of attribute type.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def type
  @type
end

Instance Method Details

#base_pathObject



88
89
90
# File 'lib/constancy/sync_target.rb', line 88

def base_path
  @base_path ||= File.join(@base_dir, self.path)
end

#chomp?Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/constancy/sync_target.rb', line 65

def chomp?
  @do_chomp
end

#clear_cacheObject



81
82
83
84
85
86
# File 'lib/constancy/sync_target.rb', line 81

def clear_cache
  @base_path = nil
  @local_files = nil
  @local_items = nil
  @remote_items = nil
end

#delete?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/constancy/sync_target.rb', line 69

def delete?
  @do_delete
end

#description(mode = :push) ⇒ Object



73
74
75
76
77
78
79
# File 'lib/constancy/sync_target.rb', line 73

def description(mode = :push)
  if mode == :pull
    "#{self.name.nil? ? '' : self.name.bold + "\n"}#{'consul'.cyan}:#{self.datacenter.green}:#{self.prefix} => #{'local'.blue}:#{self.path}"
  else
    "#{self.name.nil? ? '' : self.name.bold + "\n"}#{'local'.blue}:#{self.path} => #{'consul'.cyan}:#{self.datacenter.green}:#{self.prefix}"
  end
end

#diff(mode) ⇒ Object



154
155
156
# File 'lib/constancy/sync_target.rb', line 154

def diff(mode)
  Constancy::Diff.new(target: self, local: self.local_items, remote: self.remote_items, mode: mode)
end

#erb_enabled?Boolean

Returns:

  • (Boolean)


61
62
63
# File 'lib/constancy/sync_target.rb', line 61

def erb_enabled?
  @erb_enabled
end

#load_local_file(local_file) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/constancy/sync_target.rb', line 127

def load_local_file(local_file)
  file = File.read(local_file)

  if self.chomp?
    encoded_file = file.chomp.force_encoding(Encoding::ASCII_8BIT)
  else
    encoded_file = file.force_encoding(Encoding::ASCII_8BIT)
  end

  return ERB.new(encoded_file).result if erb_enabled?
  encoded_file
end

#local_filesObject



92
93
94
95
# File 'lib/constancy/sync_target.rb', line 92

def local_files
  # see https://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
  @local_files ||= Dir["#{self.base_path}/**{,/*/**}/*"].select { |f| File.file?(f) }
end

#local_itemsObject



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/constancy/sync_target.rb', line 97

def local_items
  return @local_items if not @local_items.nil?
  @local_items = {}

  case self.type
  when :dir
    self.local_files.each do |local_file|
      @local_items[local_file.sub(%r{^#{self.base_path}/?}, '')] =
        load_local_file(local_file)
    end

  when :file
    if File.exist?(self.base_path)
      @local_items = local_items_from_file
    end
  end

  @local_items
end

#local_items_from_fileObject



117
118
119
120
121
122
123
124
125
# File 'lib/constancy/sync_target.rb', line 117

def local_items_from_file
  if erb_enabled?
    loaded_file = YAML.load(ERB.new(File.read(self.base_path)).result)
  else
    loaded_file = YAML.load_file(self.base_path)
  end

  flatten_hash(nil, loaded_file)
end

#remote_itemsObject



140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/constancy/sync_target.rb', line 140

def remote_items
  return @remote_items if not @remote_items.nil?
  @remote_items = {}

  resp = self.consul.get(self.prefix, :recurse, dc: self.datacenter)

  return @remote_items if resp.values.nil?
  Constancy::Util.flatten_hash(resp.values).each_pair do |key, value|
    @remote_items[key.join("/")] = (value.nil? ? '' : value)
  end

  @remote_items
end