summaryrefslogtreecommitdiff
path: root/lib/leap_cli/leapfile.rb
blob: ac4023744e2ddfe7e96c21a357fcf5e8c05654ea (plain)
1
2
3
4
5
6
7
8
9
10
11
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#
# The Leapfile is the bootstrap configuration file for a LEAP provider.
#
# It is akin to a Gemfile, Rakefile, or Capfile (e.g. it is a ruby file that gets eval'ed)
#

module LeapCli
  def self.leapfile
    @leapfile ||= Leapfile.new
  end

  class Leapfile
    attr_accessor :platform_directory_path
    attr_accessor :provider_directory_path
    attr_accessor :custom_vagrant_vm_line
    attr_accessor :leap_version
    attr_accessor :log
    attr_accessor :vagrant_network
    attr_accessor :vagrant_basebox
    attr_accessor :environment

    def initialize
      @vagrant_network = '10.5.5.0/24'
    end

    #
    # The way the Leapfile handles pinning of environment (self.environment) is a little tricky.
    # If self.environment is nil, then there is no pin. If self.environment is 'default', then
    # there is a pin to the default environment. The problem is that an environment of nil
    # is used to indicate the default environment in node properties.
    #
    # This method returns the environment tag as needed when filtering nodes.
    #
    def environment_filter
      if self.environment == 'default'
        nil
      else
        self.environment
      end
    end

    def load(search_directory=nil)
      directory = File.expand_path(find_in_directory_tree('Leapfile', search_directory))
      if directory == '/'
        return nil
      else
        #
        # set up paths
        #
        @provider_directory_path = directory
        begin
          # load leaprc first, so that we can potentially access which environment is pinned in Leapfile
          # but also load leaprc last, so that it can override what is set in Leapfile.
          read_settings(leaprc_path)
        rescue StandardError
        end
        read_settings(directory + '/Leapfile')
        read_settings(leaprc_path)
        @platform_directory_path = File.expand_path(@platform_directory_path || '../leap_platform', @provider_directory_path)

        #
        # load the platform
        #
        platform_file = "#{@platform_directory_path}/platform.rb"
        unless File.exist?(platform_file)
          Util.bail! "ERROR: The file `#{platform_file}` does not exist. Please check the value of `@platform_directory_path` in `Leapfile` or `~/.leaprc`."
        end
        require "#{@platform_directory_path}/platform.rb"
        if !Leap::Platform.compatible_with_cli?(LeapCli::VERSION) ||
           !Leap::Platform.version_in_range?(LeapCli::COMPATIBLE_PLATFORM_VERSION)
          Util.bail! "This leap command (v#{LeapCli::VERSION}) " +
                     "is not compatible with the platform #{@platform_directory_path} (v#{Leap::Platform.version}).\n   " +
                     "You need either leap command #{Leap::Platform.compatible_cli.first} to #{Leap::Platform.compatible_cli.last} or " +
                     "platform version #{LeapCli::COMPATIBLE_PLATFORM_VERSION.first} to #{LeapCli::COMPATIBLE_PLATFORM_VERSION.last}"
        end
        @valid = true
        return @valid
      end
    end

    def set(property, value)
      edit_leaprc(property, value)
    end

    def unset(property)
      edit_leaprc(property)
    end

    def valid?
      !!@valid
    end

    private

    #
    # adds or removes a line to .leaprc for this particular provider directory.
    # if value is nil, the line is removed. if not nil, it is added or replaced.
    #
    def edit_leaprc(property, value=nil)
      file_path = leaprc_path
      lines = []
      if File.exist?(file_path)
        regexp = /self\.#{Regexp.escape(property)} = .*? if @provider_directory_path == '#{Regexp.escape(@provider_directory_path)}'/
        File.readlines(file_path).each do |line|
          unless line =~ regexp
            lines << line
          end
        end
      end
      unless value.nil?
        lines << "self.#{property} = #{value.inspect} if @provider_directory_path == '#{@provider_directory_path}'\n"
      end
      File.open(file_path, 'w') do |f|
        f.write(lines.join)
      end
    rescue Errno::EACCES, IOError => exc
      Util::bail! :error, "trying to save ~/.leaprc (#{exc})."
    end

    def leaprc_path
      File.join(ENV['HOME'], '.leaprc')
    end

    def read_settings(file)
      if File.exist? file
        Util::log 2, :read, file
        instance_eval(File.read(file), file)
        validate(file)
      end
    end

    def find_in_directory_tree(filename, directory_tree=nil)
      search_dir = directory_tree || Dir.pwd
      while search_dir != "/"
        Dir.foreach(search_dir) do |f|
          return search_dir if f == filename
        end
        search_dir = File.dirname(search_dir)
      end
      return search_dir
    end

    PRIVATE_IP_RANGES = /(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/

    def validate(file)
      Util::assert! vagrant_network =~ PRIVATE_IP_RANGES do
        Util::log 0, :error, "in #{file}: vagrant_network is not a local private network"
      end
    end

  end
end