Class: OpenShift::UnixUser

Inherits:
Model
  • Object
show all
Includes:
OpenShift::Utils::ShellExec
Defined in:
lib/openshift-origin-node/model/unix_user.rb

Overview

Unix User

Represents a user account on the system.

Constant Summary collapse

DEFAULT_SKEL_DIR =
File.join(OpenShift::Config::CONF_DIR,"skel")

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from OpenShift::Utils::ShellExec

run_as, shellCmd, #shellCmd

Constructor Details

#initialize(application_uuid, container_uuid, user_uid = nil, app_name = nil, container_name = nil, namespace = nil, quota_blocks = nil, quota_files = nil, debug = false) ⇒ UnixUser

Returns a new instance of UnixUser.



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
# File 'lib/openshift-origin-node/model/unix_user.rb', line 43

def initialize(application_uuid, container_uuid, user_uid=nil,
    app_name=nil, container_name=nil, namespace=nil, quota_blocks=nil, quota_files=nil, debug=false)
  Syslog.open('openshift-origin-node', Syslog::LOG_PID, Syslog::LOG_LOCAL0) unless Syslog.opened?

  @config = OpenShift::Config.new

  @container_uuid = container_uuid
  @application_uuid = application_uuid
  @uuid = container_uuid
  @app_name = app_name
  @container_name = container_name
  @namespace = namespace
  @quota_blocks = quota_blocks
  @quota_files = quota_files
  @debug = debug

  begin
     = Etc.getpwnam(@uuid)
    @uid = .uid
    @gid = .gid
    @gecos = .gecos
    @homedir = "#{.dir}/"
  rescue ArgumentError => e
    @uid = user_uid
    @gid = user_uid
    @gecos = nil
    @homedir = nil
  end
end

Instance Attribute Details

#app_nameObject (readonly)

Returns the value of attribute app_name.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def app_name
  @app_name
end

#application_uuidObject (readonly)

Returns the value of attribute application_uuid.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def application_uuid
  @application_uuid
end

#container_nameObject (readonly)

Returns the value of attribute container_name.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def container_name
  @container_name
end

#container_uuidObject (readonly)

Returns the value of attribute container_uuid.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def container_uuid
  @container_uuid
end

#debugObject

Returns the value of attribute debug.



39
40
41
# File 'lib/openshift-origin-node/model/unix_user.rb', line 39

def debug
  @debug
end

#gecosObject (readonly)

Returns the value of attribute gecos.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def gecos
  @gecos
end

#gidObject (readonly)

Returns the value of attribute gid.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def gid
  @gid
end

#homedirObject (readonly)

Returns the value of attribute homedir.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def homedir
  @homedir
end

#namespaceObject (readonly)

Returns the value of attribute namespace.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def namespace
  @namespace
end

#quota_blocksObject (readonly)

Returns the value of attribute quota_blocks.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def quota_blocks
  @quota_blocks
end

#quota_filesObject (readonly)

Returns the value of attribute quota_files.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def quota_files
  @quota_files
end

#uidObject (readonly)

Returns the value of attribute uid.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def uid
  @uid
end

#uuidObject (readonly)

Returns the value of attribute uuid.



36
37
38
# File 'lib/openshift-origin-node/model/unix_user.rb', line 36

def uuid
  @uuid
end

Class Method Details

.kill_procs(id) ⇒ Object

Private: Kill all processes for a given gear

Kill all processes owned by the uid or uuid. No reason for graceful shutdown first, the directories and user are going

to be removed from the system.

Examples: kill_gear_procs

=> true
pkill -u id

Raises exception on error.



608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
# File 'lib/openshift-origin-node/model/unix_user.rb', line 608

def self.kill_procs(id)
  if id.nil? or id == ""
    raise ArgumentError, "Supplied ID must be a uid."
  end

  # Give it a good try to delete all processes.
  # This abuse is neccessary to release locks on polyinstantiated
  #    directories by pam_namespace.
  out = err = rc = nil
  10.times do |i|
    OpenShift::Utils::ShellExec.shellCmd(%{/usr/bin/pkill -9 -u #{id}})
    out,err,rc = OpenShift::Utils::ShellExec.shellCmd(%{/usr/bin/pgrep -u #{id}})
    break unless 0 == rc

    Syslog.alert "ERROR: attempt #{i}/10 there are running \"killed\" processes for #{id}(#{rc}): stdout: #{out} stderr: #{err}"
    sleep 0.5
  end

  # looks backwards but 0 implies processes still existed
  if 0 == rc
    out,err,rc = OpenShift::Utils::ShellExec.shellCmd("ps -u #{@uid} -o state,pid,ppid,cmd")
    Syslog.alert "ERROR: failed to kill all processes for #{id}(#{rc}): stdout: #{out} stderr: #{err}"
  end
end

Instance Method Details

#add_broker_auth(iv, token) ⇒ Object

Public: Add broker authorization keys so gear can communicate with

broker.

iv - A String value for the IV file. token - A String value for the token file.

Examples

add_broker_auth('ivvalue', 'tokenvalue')
# => ["/var/lib/openshift/UUID/.auth/iv",
      "/var/lib/openshift/UUID/.auth/token"]

Returns An Array of Strings for the newly created auth files



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/openshift-origin-node/model/unix_user.rb', line 375

def add_broker_auth(iv,token)
  broker_auth_dir=File.join(@homedir,'.auth')
  FileUtils.mkdir_p broker_auth_dir
  File.open(File.join(broker_auth_dir, 'iv'),
        File::WRONLY|File::TRUNC|File::CREAT) do |file|
    file.write iv
  end
  File.open(File.join(broker_auth_dir, 'token'),
        File::WRONLY|File::TRUNC|File::CREAT) do |file|
    file.write token
  end

  FileUtils.chown_R("root", @uuid,broker_auth_dir)
  FileUtils.chmod(0o0750, broker_auth_dir)
  FileUtils.chmod(0o0640, Dir.glob("#{broker_auth_dir}/*"))
end

#add_env_var(key, value, prefix_cloud_name = false, &blk) ⇒ Object

Public: Add an environment variable to a given gear.

key - The String value of target environment variable. value - The String value to place inside the environment variable. prefix_cloud_name - The String value to append in front of key.

Examples

add_env_var('mysql-5.3')
# => 36

Returns the Integer value for how many bytes got written or raises on failure.



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/openshift-origin-node/model/unix_user.rb', line 310

def add_env_var(key, value, prefix_cloud_name = false, &blk)
  env_dir = File.join(@homedir,'.env/')
  if prefix_cloud_name
    key = (@config.get('CLOUD_NAME') || 'OPENSHIFT') + "_#{key}"
  end
  filename = File.join(env_dir, key)
  File.open(filename,
      File::WRONLY|File::TRUNC|File::CREAT) do |file|
        file.write "export #{key}='#{value}'"
    end

  if block_given?
    blk.call(value)
  end
end

#add_ssh_key(key, key_type = nil, comment = nil) ⇒ Object

Public: Append an SSH key to a users authorized_keys file

key - The String value of the ssh key. key_type - The String value of the key type ssh-(rsa|dss)). comment - The String value of the comment to append to the key.

Examples

add_ssh_key('AAAAB3NzaC1yc2EAAAADAQABAAABAQDE0DfenPIHn5Bq/...',
            'ssh-rsa',
            '[email protected]')
# => nil

Returns nil on Success or raises on Failure



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/openshift-origin-node/model/unix_user.rb', line 250

def add_ssh_key(key, key_type=nil, comment=nil)
  comment = "" unless comment
  self.class.notify_observers(:before_add_ssh_key, self, key)

  authorized_keys_file = File.join(@homedir, ".ssh", "authorized_keys")
  keys = read_ssh_keys authorized_keys_file
  key_type    = "ssh-rsa" if key_type.to_s.strip.length == 0
  cloud_name  = @config.get("CLOUD_NAME") || "OPENSHIFT"
  ssh_comment = "#{cloud_name}-#{@uuid}#{comment}"
  shell       = @config.get("GEAR_SHELL") || "/bin/bash"
  cmd_entry   = "command=\"#{shell}\",no-X11-forwarding #{key_type} #{key} #{ssh_comment}"

  keys[ssh_comment] = cmd_entry
  write_ssh_keys authorized_keys_file, keys

  self.class.notify_observers(:after_add_ssh_key, self, key)
end

#createObject

Public: Create an empty gear.

Examples

create
# => nil
# a user
# Setup permissions

Returns nil on Success or raises on Failure



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
# File 'lib/openshift-origin-node/model/unix_user.rb', line 87

def create
  skel_dir = @config.get("GEAR_SKEL_DIR") || DEFAULT_SKEL_DIR
  shell    = @config.get("GEAR_SHELL")     || "/bin/bash"
  gecos    = @config.get("GEAR_GECOS")     || "OO application container"
  notify_observers(:before_unix_user_create)
  basedir = @config.get("GEAR_BASE_DIR")

  # lock to prevent race condition between create and delete of gear
  uuid_lock_file = "/var/lock/oo-create.#{@uuid}"
  File.open(uuid_lock_file, File::RDWR|File::CREAT, 0o0600) do | uuid_lock |
    uuid_lock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
    uuid_lock.flock(File::LOCK_EX)

    # Lock to prevent race condition on obtaining a UNIX user uid.
    # When running without districts, there is a simple search on the
    #   passwd file for the next available uid.
    File.open("/var/lock/oo-create", File::RDWR|File::CREAT, 0o0600) do | uid_lock |
      uid_lock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
      uid_lock.flock(File::LOCK_EX)

      unless @uid
        @uid = @gid = next_uid
      end

      unless @homedir
        @homedir = File.join(basedir,@uuid)
      end

      cmd = %{useradd -u #{@uid} \
              -d #{@homedir} \
              -s #{shell} \
              -c '#{gecos}' \
              -m \
              -k #{skel_dir} \
              #{@uuid}}
      out,err,rc = shellCmd(cmd)
      raise UserCreationException.new(
              "ERROR: unable to create user account(#{rc}): #{cmd.squeeze(" ")} stdout: #{out} stderr: #{err}"
              ) unless rc == 0

      FileUtils.chown("root", @uuid, @homedir)
      FileUtils.chmod 0o0750, @homedir

      if @config.get("CREATE_APP_SYMLINKS").to_i == 1
        unobfuscated = File.join(File.dirname(@homedir),"#{@container_name}-#{namespace}")
        if not File.exists? unobfuscated
          FileUtils.ln_s File.basename(@homedir), unobfuscated, :force=>true
        end
      end
    end
    notify_observers(:after_unix_user_create)
    initialize_homedir(basedir, @homedir, @config.get("CARTRIDGE_BASE_PATH"))
    initialize_openshift_port_proxy

    uuid_lock.flock(File::LOCK_UN)
    File.unlink(uuid_lock_file)
  end
end

#destroyObject

Public: Destroys a gear stopping all processes and removing all files

The order of the calls and gyrations done in this code is to prevent

pam_namespace from locking polyinstantiated directories during
their deletion. If you see "broken" gears, i.e. ~uuid/.tmp and
 ~/uuid/.sandbox after #destroy has been called, this method is broken.

See Bug 853582 for history.

Examples

destroy
# => nil

Returns nil on Success or raises on Failure



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/openshift-origin-node/model/unix_user.rb', line 160

def destroy
  if @uid.nil? and (not File.directory?(@homedir.to_s))
    # gear seems to have been destroyed already... suppress any error
    # TODO : remove remaining stuff if it exists, e.g. .httpd/#{uuid}* etc
    return nil
  end
  raise UserDeletionException.new(
        "ERROR: unable to destroy user account #{@uuid}"
        ) if @uid.nil? || @homedir.nil? || @uuid.nil?

  # Don't try to delete a gear that is being scaled-up|created|deleted
  uuid_lock_file = "/var/lock/oo-create.#{@uuid}"
  File.open(uuid_lock_file, File::RDWR|File::CREAT, 0o0600) do | lock |
    lock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
    lock.flock(File::LOCK_EX)

    # These calls and their order is designed to release pam_namespace's
    #   locks on .tmp and .sandbox. Change then at your peril. 
    #
    # 1. Kill off the easy processes
    # 2. Lock down the user from creating new processes (cgroups freeze, nprocs 0)
    # 3. Attempt to move any processes that didn't die into state 'D' (re: cgroups freeze)
    self.class.kill_procs(@uid)
    notify_observers(:before_unix_user_destroy)
    self.class.kill_procs(@uid)

    purge_sysvipc(uuid)
    initialize_openshift_port_proxy

    if @config.get("CREATE_APP_SYMLINKS").to_i == 1
      Dir.foreach(File.dirname(@homedir)) do |dent|
        unobfuscate = File.join(File.dirname(@homedir), dent)
        if (File.symlink?(unobfuscate)) &&
            (File.readlink(unobfuscate) == File.basename(@homedir))
          File.unlink(unobfuscate)
        end
      end
    end

    OpenShift::FrontendHttpServer.new(@container_uuid,@container_name,@namespace).destroy

    dirs = list_home_dir(@homedir)
    cmd = "userdel -f \"#{@uuid}\""
    out,err,rc = shellCmd(cmd)
    raise UserDeletionException.new(
          "ERROR: unable to destroy user account(#{rc}): #{cmd} stdout: #{out} stderr: #{err}"
          ) unless rc == 0

    # 1. Don't believe everything you read on the userdel man page...
    # 2. If there are any active processes left pam_namespace is not going
    #      to let polyinstantiated directories be deleted.
    FileUtils.rm_rf(@homedir)
    if File.exists?(@homedir)
      # Ops likes the verbose verbage
      Syslog.alert %Q{
1st attempt to remove \'#{@homedir}\' from filesystem failed.
Dir(before)   #{@uuid}/#{@uid} => #{dirs}
Dir(after)    #{@uuid}/#{@uid} => #{list_home_dir(@homedir)}
      }
    end

    # release resources (cgroups thaw), this causes Zombies to get killed
    notify_observers(:after_unix_user_destroy)

    # try one last time...
    if File.exists?(@homedir)
      sleep(5)                    # don't fear the reaper
      FileUtils.rm_rf(@homedir)   # This is our last chance to nuke the polyinstantiated directories
      Syslog.alert "2nd attempt to remove \'#{@homedir}\' from filesystem failed." if File.exists?(@homedir)
    end

    lock.flock(File::LOCK_UN)
    File.unlink(uuid_lock_file)
  end
end

#get_mcs_label(uid) ⇒ String

private: Determine the MCS label for a given uid

Parameters:

  • The (Integer)

    user ID

Returns:

  • (String)

    The SELinux MCS label



703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
# File 'lib/openshift-origin-node/model/unix_user.rb', line 703

def get_mcs_label(uid)
  if ((uid.to_i < 0) || (uid.to_i>523776))
    raise ArgumentError, "Supplied UID must be between 0 and 523776."
  end

  setsize=1023
  tier=setsize
  ord=uid.to_i
  while ord > tier
    ord -= tier
    tier -= 1
  end
  tier = setsize - tier
  "s0:c#{tier},c#{ord + tier}"
end

#initialize_homedir(basedir, homedir, cart_basedir) ⇒ Object

Private: Create and populate the users home dir.

Examples

initialize_homedir
# => nil
# Creates:
# ~
# ~/.tmp/
# ~/.sandbox/$uuid
# ~/.env/
# APP_UUID, GEAR_UUID, APP_NAME, APP_DNS, HOMEDIR, DATA_DIR, \
#   GEAR_DNS, GEAR_NAME, PATH, REPO_DIR, TMP_DIR, HISTFILE
# ~/app-root
# ~/app-root/data
# ~/app-root/runtime/repo
# ~/app-root/repo -> runtime/repo
# ~/app-root/runtime/data -> ../data

Returns nil on Success and raises on Failure.



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
# File 'lib/openshift-origin-node/model/unix_user.rb', line 426

def initialize_homedir(basedir, homedir, cart_basedir)
  @homedir = homedir
  notify_observers(:before_initialize_homedir)
  homedir = homedir.end_with?('/') ? homedir : homedir + '/'

  tmp_dir = File.join(homedir, ".tmp")
  # Required for polyinstantiated tmp dirs to work
  FileUtils.mkdir_p tmp_dir
  FileUtils.chmod(0o0000, tmp_dir)

  sandbox_dir = File.join(homedir, ".sandbox")
  FileUtils.mkdir_p sandbox_dir
  FileUtils.chmod(0o0000, sandbox_dir)

  sandbox_uuid_dir = File.join(sandbox_dir, @uuid)
  FileUtils.mkdir_p sandbox_uuid_dir
  FileUtils.chmod(0o1755, sandbox_uuid_dir)

  env_dir = File.join(homedir, ".env")
  FileUtils.mkdir_p(env_dir)
  FileUtils.chmod(0o0750, env_dir)
  FileUtils.chown(nil, @uuid, env_dir)

  ssh_dir = File.join(homedir, ".ssh")
  FileUtils.mkdir_p(ssh_dir)
  FileUtils.chmod(0o0750, ssh_dir)
  FileUtils.chown(nil, @uuid, ssh_dir)

  geardir = File.join(homedir, @container_name, "/")
  gearappdir = File.join(homedir, "app-root", "/")

  add_env_var("APP_DNS",
              "#{@app_name}-#{@namespace}.#{@config.get("CLOUD_DOMAIN")}",
              true)
  add_env_var("APP_NAME", @app_name, true)
  add_env_var("APP_UUID", @application_uuid, true)

  data_dir = File.join(gearappdir, "data", "/")
  add_env_var("DATA_DIR", data_dir, true) {|v|
    FileUtils.mkdir_p(v, :verbose => @debug)
  }
  add_env_var("HISTFILE", File.join(data_dir, ".bash_history"))
  profile = File.join(data_dir, ".bash_profile")
  File.open(profile, File::WRONLY|File::TRUNC|File::CREAT, 0o0600) {|file|
    file.write %Q{
# Warning: Be careful with modifications to this file,
#          Your changes may cause your application to fail.
}
  }
  FileUtils.chown(@uuid, @uuid, profile, :verbose => @debug)


  add_env_var("GEAR_DNS",
              "#{@container_name}-#{@namespace}.#{@config.get("CLOUD_DOMAIN")}",
              true)
  add_env_var("GEAR_NAME", @container_name, true)
  add_env_var("GEAR_UUID", @container_uuid, true)

  add_env_var("HOMEDIR", homedir, true)

  add_env_var("PATH",
              "#{cart_basedir}abstract-httpd/info/bin/:#{cart_basedir}abstract/info/bin/:$PATH",
              false)

  add_env_var("REPO_DIR", File.join(gearappdir, "runtime", "repo", "/"), true) {|v|
    FileUtils.mkdir_p(v, :verbose => @debug)
    FileUtils.cd gearappdir do |d|
      FileUtils.ln_s("runtime/repo", "repo", :verbose => @debug)
    end
    FileUtils.cd File.join(gearappdir, "runtime") do |d|
      FileUtils.ln_s("../data", "data", :verbose => @debug)
    end
  }

  add_env_var("TMP_DIR", "/tmp/", true)

  # Update all directory entries ~/app-root/*
  Dir[gearappdir + "/*"].entries.reject{|e| [".", ".."].include? e}.each {|e|
    FileUtils.chmod_R(0o0750, e, :verbose => @debug)
    FileUtils.chown_R(@uuid, @uuid, e, :verbose => @debug)
  }
  FileUtils.chown(nil, @uuid, gearappdir, :verbose => @debug)
  raise "Failed to instantiate gear: missing application directory (#{gearappdir})" unless File.exist?(gearappdir)

  state_file = File.join(gearappdir, "runtime", ".state")
  File.open(state_file, File::WRONLY|File::TRUNC|File::CREAT, 0o0660) {|file|
    file.write "new\n"
  }
  FileUtils.chown(@uuid, @uuid, state_file, :verbose => @debug)

  OpenShift::FrontendHttpServer.new(@container_uuid,@container_name,@namespace).create

  # Fix SELinux context
  set_selinux_context(homedir)

  notify_observers(:after_initialize_homedir)
end

#initialize_openshift_port_proxyObject

Private: Initialize OpenShift Port Proxy for this gear

The port proxy range is determined by configuration and must produce identical results to the abstract cartridge provided range.

Examples: initialize_openshift_port_proxy

=> true
service openshift_port_proxy setproxy 35000 delete 35001 delete etc...

Returns:

true   - port proxy could be initialized properly
false  - port proxy could not be initialized properly


560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
# File 'lib/openshift-origin-node/model/unix_user.rb', line 560

def initialize_openshift_port_proxy
  notify_observers(:before_initialize_openshift_port_proxy)

  port_begin = (@config.get("PORT_BEGIN") || "35531").to_i
  ports_per_user = (@config.get("PORTS_PER_USER") || "5").to_i

  # Note, due to a mismatch between dev and prod this is
  # intentionally not GEAR_MIN_UID and the range must
  # wrap back around on itself.
  uid_begin = (@config.get("UID_BEGIN") || "500").to_i

  wrap_uid = ((65536 - port_begin)/ports_per_user)+uid_begin

  if @uid >= wrap_uid
    tuid = @uid - wrap_uid + uid_begin
  else
    tuid = @uid
  end

  proxy_port_begin = (tuid-uid_begin) * ports_per_user + port_begin

  proxy_port_range = (proxy_port_begin ... (proxy_port_begin + ports_per_user))

  cmd = %{openshift-port-proxy-cfg setproxy}
  proxy_port_range.each { |i| cmd << " #{i} delete" }
  out, err, rc = shellCmd(cmd)
  Syslog.warning(
        "WARNING: openshift-port-proxy-cfg failed(#{rc}): #{cmd} stdout: #{out} stderr: #{err}"
        ) unless 0 == rc

  notify_observers(:after_initialize_openshift_port_proxy)
  return rc == 0
end

#list_home_dir(home_dir) ⇒ String

Public: list directories (cartridges) in home directory

Parameters:

  • home (String)

    directory

Returns:

  • (String)

    comma separated list of directories



329
330
331
332
333
334
335
336
# File 'lib/openshift-origin-node/model/unix_user.rb', line 329

def list_home_dir(home_dir)
  results = []
  Dir.foreach(home_dir) do |entry|
    #next if entry =~ /^\.{1,2}/   # Ignore ".", "..", or hidden files
    results << entry
  end
  results.join(', ')
end

#nameObject



73
74
75
# File 'lib/openshift-origin-node/model/unix_user.rb', line 73

def name
  @uuid
end

#next_uidObject

Private: Determine next available user id. This is usually determined

and provided by the broker but is auto determined if not
provided.

Examples:

next_uid =>
# => 504

Returns Integer value for next available uid.



533
534
535
536
537
538
539
540
541
542
543
544
# File 'lib/openshift-origin-node/model/unix_user.rb', line 533

def next_uid
  uids = IO.readlines("/etc/passwd").map{ |line| line.split(":")[2].to_i }
  gids = IO.readlines("/etc/group").map{ |line| line.split(":")[2].to_i }
  min_uid = (@config.get("GEAR_MIN_UID") || "500").to_i
  max_uid = (@config.get("GEAR_MAX_UID") || "1500").to_i

  (min_uid..max_uid).each do |i|
    if !uids.include?(i) and !gids.include?(i)
      return i
    end
  end
end

#purge_sysvipc(id) ⇒ Object

Private: Purge IPC entities for a given gear

Enumerate and remove all IPC entities for a given user ID or user name.

Examples: purge_sysvipc

=> true
ipcs -c
ipcrm -s id
ipcrm -m id

Raises exception on error.



647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
# File 'lib/openshift-origin-node/model/unix_user.rb', line 647

def purge_sysvipc(id)
  if id.nil? or id == ""
    raise ArgumentError.new("Supplied ID must be a user name or uid.")
  end

  ['-m', '-q', '-s' ].each do |ipctype|
    out,err,rc=shellCmd(%{/usr/bin/ipcs -c #{ipctype} 2> /dev/null})
    out.lines do |ipcl|
      next unless ipcl=~/^\d/
      ipcent = ipcl.split
      if ipcent[2] == id
        # The ID may already be gone
        shellCmd(%{/usr/bin/ipcrm #{ipctype} #{ipcent[0]}})
      end
    end
  end
end

#read_ssh_keys(authorized_keys_file) ⇒ Hash

private: Read ssh authorized_keys file

Parameters:

  • authorized_keys_file (String)

    ssh authorized_keys path

Returns:

  • (Hash)

    authorized keys with the comment field as the key



687
688
689
690
691
692
693
694
695
696
697
# File 'lib/openshift-origin-node/model/unix_user.rb', line 687

def read_ssh_keys(authorized_keys_file)
  keys = {}
  if File.exists? authorized_keys_file
    File.open(authorized_keys_file, File::RDONLY).each_line do | line |
      options, key_type, key, comment = line.split
      keys[comment] = line.chomp
    end
    FileUtils.chown_R('root', @uuid, authorized_keys_file)
  end
  keys
end

#remove_broker_authObject

Public: Remove broker authentication keys from gear.

Examples

remove_broker_auth
# => nil

Returns nil on Success and false on Failure



399
400
401
402
403
# File 'lib/openshift-origin-node/model/unix_user.rb', line 399

def remove_broker_auth
  broker_auth_dir=File.join(@homedir, '.auth')
  FileUtils.rm_rf broker_auth_dir
  File.exists?(broker_auth_dir) ? false : true
end

#remove_env_var(key, prefix_cloud_name = false) ⇒ Object

Public: Remove an environment variable from a given gear.

key - String name of the environment variable to remove. prefix_cloud_name - String prefix to append to key.

Examples

remove_env_var('OPENSHIFT_MONGODB_DB_URL')
# => nil

Returns an nil on success and false on failure.



349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/openshift-origin-node/model/unix_user.rb', line 349

def remove_env_var(key, prefix_cloud_name=false)
  status = false
  [".env", ".env/.uservars"].each do |path|
    env_dir = File.join(@homedir,path)
    if prefix_cloud_name
      key = (@config.get("CLOUD_NAME") || "OPENSHIFT") + "_#{key}"
    end
    env_file_path = File.join(env_dir, key)
    FileUtils.rm_f env_file_path
    status = status ? true : (File.exists?(env_file_path) ? false : true)
  end
  status
end

#remove_ssh_key(key, comment = nil) ⇒ Object

Public: Remove an SSH key from a users authorized_keys file.

key - The String value of the ssh key. comment - The String value of the comment associated with the key.

Examples

remove_ssh_key('AAAAB3NzaC1yc2EAAAADAQABAAABAQDE0DfenPIHn5Bq/...',
            '[email protected]')
# => nil

Returns nil on Success or raises on Failure



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/openshift-origin-node/model/unix_user.rb', line 280

def remove_ssh_key(key, comment=nil)
  self.class.notify_observers(:before_remove_ssh_key, self, key)

  authorized_keys_file = File.join(@homedir, ".ssh", "authorized_keys")
  keys = read_ssh_keys authorized_keys_file

  if comment
    keys.delete_if{ |k, v| v.include?(key) && v.include?(comment)}
  else
    keys.delete_if{ |k, v| v.include?(key)}
  end

  write_ssh_keys authorized_keys_file, keys

  self.class.notify_observers(:after_remove_ssh_key, self, key)
end

#set_selinux_context(path) ⇒ Object

private: Set the SELinux context on a file or directory

Parameters:

  • The (Integer)

    user ID



722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
# File 'lib/openshift-origin-node/model/unix_user.rb', line 722

def set_selinux_context(path)
  mcs_label=get_mcs_label(@uid)

  cmd = "restorecon -R #{path}"
  out, err, rc = shellCmd(cmd)
  Syslog.err(
            "ERROR: unable to restorecon user homedir(#{rc}): #{cmd} stdout: #{out} stderr: #{err}"
            ) unless 0 == rc
  cmd = "chcon -R -l #{mcs_label} #{path}/*"

  out, err, rc = shellCmd(cmd)
  Syslog.err(
            "ERROR: unable to chcon user homedir(#{rc}): #{cmd} stdout: #{out} stderr: #{err}"
            ) unless 0 == rc
end

#write_ssh_keys(authorized_keys_file, keys) ⇒ Hash

private: Write ssh authorized_keys file

Parameters:

  • authorized_keys_file (String)

    ssh authorized_keys path

  • keys (Hash)

    authorized keys with the comment field as the key

Returns:

  • (Hash)

    authorized keys with the comment field as the key



670
671
672
673
674
675
676
677
678
679
680
681
# File 'lib/openshift-origin-node/model/unix_user.rb', line 670

def write_ssh_keys(authorized_keys_file, keys)
  File.open(authorized_keys_file,
            File::WRONLY|File::TRUNC|File::CREAT,
            0o0440) do |file|
    file.write(keys.values.join("\n"))
    file.write("\n")
  end
  FileUtils.chown_R('root', @uuid, authorized_keys_file)
  set_selinux_context(authorized_keys_file)

  keys
end