networkmanager-dbus 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/Guardfile +5 -1
  2. data/README.md +20 -2
  3. data/Rakefile +13 -1
  4. data/TODO.md +3 -3
  5. data/examples/change_ip.rb +17 -0
  6. data/examples/connectivity.rb +1 -1
  7. data/lib/dbus_interface.rb +14 -5
  8. data/lib/dbus_interface/class.rb +28 -4
  9. data/lib/dbus_interface/connection.rb +58 -0
  10. data/lib/dbus_interface/object.rb +15 -7
  11. data/lib/network_manager.rb +3 -2
  12. data/lib/network_manager/dbus.rb +2 -0
  13. data/lib/network_manager/dbus/device.rb +9 -7
  14. data/lib/network_manager/dbus/root.rb +8 -4
  15. data/lib/network_manager/dbus/settings.rb +18 -5
  16. data/lib/network_manager/dbus/settings_connection.rb +86 -0
  17. data/lib/network_manager/ip4_config.rb +33 -0
  18. data/lib/network_manager/version.rb +1 -1
  19. data/lib/networkmanager-dbus.rb +1 -1
  20. data/networkmanager-dbus.gemspec +4 -0
  21. data/script/console +7 -0
  22. data/script/spec_server +1 -0
  23. data/spec/fixtures/active_connections.yml +10 -0
  24. data/spec/fixtures/devices.yml +18 -37
  25. data/spec/fixtures/dhcp4_configs.yml +17 -0
  26. data/spec/fixtures/ip4_configs.yml +7 -0
  27. data/spec/fixtures/settings.yml +4 -14
  28. data/spec/fixtures/settings_connections.yml +10 -0
  29. data/spec/lib/dbus_interface/class_spec.rb +31 -0
  30. data/spec/lib/dbus_interface/object_spec.rb +32 -0
  31. data/spec/{network_manager → lib/network_manager}/dbus/active_connection_spec.rb +6 -6
  32. data/spec/lib/network_manager/dbus/device_spec.rb +58 -0
  33. data/spec/lib/network_manager/dbus/dhcp4_config_spec.rb +19 -0
  34. data/spec/lib/network_manager/dbus/ethernet_device_spec.rb +14 -0
  35. data/spec/lib/network_manager/dbus/ip4_config_spec.rb +19 -0
  36. data/spec/lib/network_manager/dbus/root_spec.rb +38 -0
  37. data/spec/lib/network_manager/dbus/settings_connection_spec.rb +69 -0
  38. data/spec/lib/network_manager/dbus/settings_spec.rb +53 -0
  39. data/spec/lib/network_manager/ip4_config_spec.rb +27 -0
  40. data/spec/{network_manager_spec.rb → lib/network_manager_spec.rb} +2 -0
  41. data/spec/mocks/dbus/ethernet_device_mock.rb +5 -0
  42. data/spec/mocks/dbus/root_mock.rb +14 -0
  43. data/spec/mocks/dbus/settings_connection_mock.rb +21 -0
  44. data/spec/mocks/dbus/settings_mock.rb +9 -0
  45. data/spec/mocks/dbus_mock.rb +33 -0
  46. data/spec/mocks/init.rb +18 -0
  47. data/spec/mocks/system_bus_mock.rb +5 -0
  48. data/spec/mocks/system_bus_service_mock.rb +9 -0
  49. data/spec/spec_helper.rb +22 -3
  50. data/spec/support/fixture_helper.rb +21 -4
  51. metadata +96 -28
  52. data/lib/network_manager/ip4_helper.rb +0 -14
  53. data/spec/network_manager/dbus/device_spec.rb +0 -36
  54. data/spec/network_manager/dbus/dhcp4_config_spec.rb +0 -14
  55. data/spec/network_manager/dbus/ethernet_device_spec.rb +0 -21
  56. data/spec/network_manager/dbus/ip4_config_spec.rb +0 -14
  57. data/spec/network_manager/dbus/root_spec.rb +0 -22
  58. data/spec/network_manager/dbus/settings_connection_spec.rb +0 -13
  59. data/spec/network_manager/dbus/settings_spec.rb +0 -30
data/Guardfile CHANGED
@@ -2,5 +2,9 @@
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
4
  guard 'shell' do
5
- watch(%r{^*.(rb|yml|file)$}) { `rake spec:remote` }
5
+ watch(%r{^*.(rb|yml|file)$}) do
6
+ #`rake spec:remote`
7
+ ENV['RSPEC_FORMAT'] = 'growl'
8
+ `rspec`
9
+ end
6
10
  end
data/README.md CHANGED
@@ -1,7 +1,18 @@
1
+ THIS IS ALPHA STUFF :)
2
+
3
+ see [TODOs](TODO.md)
4
+
5
+ [![Travis-CI Build Status](https://secure.travis-ci.org/dpree/networkmanager-dbus.png)](https://secure.travis-ci.org/dpree/networkmanager-dbus)
6
+
1
7
  # NetworkManager-Ruby
2
8
 
3
9
  This library provides a Ruby API to NetworkManager using its DBus Interface.
4
10
 
11
+ Written using the NetworkManager DBus API Documentation v0.9
12
+
13
+ * [General API](http://projects.gnome.org/NetworkManager/developers/api/09/spec.html)
14
+ * [Details](http://projects.gnome.org/NetworkManager/developers/api/09/ref-settings.html)
15
+
5
16
  ## Installation
6
17
 
7
18
  Please make sure that you have `dbus` and `networkmanager` installed on the machine
@@ -22,7 +33,7 @@ please have a look at the `examples` folder and the `specs`.
22
33
 
23
34
  Development currently happens from my OSX machine where no dbus/networkmanager
24
35
  is running. Therefore, i hacked some scripts together to be able to run rspec
25
- over the wire
36
+ over the wire.
26
37
 
27
38
  On the remote-machine (linux, dbus, networkmanager)
28
39
 
@@ -32,6 +43,13 @@ On the local-machine (osx)
32
43
 
33
44
  `guard`
34
45
 
46
+ # Thanks
47
+
48
+ to the guys from IRC channel #nm at irc.freenode.net
49
+
50
+ * dbcw
51
+ * jklimes
52
+
35
53
  # License
36
54
 
37
- Please see file `MIT-LICENSE`. Copyright 2011 Jens Bissinger.
55
+ Copyright 2011 Jens Bissinger. All rights reserved. [MIT-LICENSE](MIT-LICENSE)
data/Rakefile CHANGED
@@ -1,5 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
+ require 'bundler'
4
+ Bundler.require :development
5
+
3
6
  def pump_dumps(dumps)
4
7
  dumps.each do |obj|
5
8
  case obj['action']
@@ -40,7 +43,7 @@ namespace :spec do
40
43
  desc 'run specs on a remote server (script/spec_server)'
41
44
  task :remote do
42
45
  begin
43
- client = MarilynRPC::NativeClient.connect_tcp('192.168.56.101', 8483)
46
+ client = ::MarilynRPC::NativeClient.connect_tcp('192.168.56.101', 8483)
44
47
  runner = client.for :rspec
45
48
  json = runner.run
46
49
  begin
@@ -63,3 +66,12 @@ namespace :spec do
63
66
  end
64
67
  end
65
68
 
69
+ require 'rspec/core/rake_task'
70
+ desc 'Default: run specs.'
71
+ desc "Run specs"
72
+ RSpec::Core::RakeTask.new(:spec) do |t|
73
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
74
+ # Put spec opts in a file named .rspec in root
75
+ end
76
+ task :default => :spec
77
+
data/TODO.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # TODOs
2
2
 
3
3
  * more specs :)
4
- * make the specs run without actual dbus connection
5
- * mock networkmanager dbus api
6
- * maybe travisci
4
+ * cleanup specs
5
+ * better mocking
6
+ * refactor integration specs
7
7
  * add missing interfaces
8
8
  * different device types
9
9
  * vpn
@@ -0,0 +1,17 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '../lib/network_manager')
2
+
3
+ # the first setting (hopefully a eth0 default foo)
4
+ con = NetworkManager::DBus::Settings.connections.first
5
+
6
+ # new ip4 config
7
+ # ip + netmask + gateway
8
+ ip4 = NetworkManager::Ip4Config.from_dot_notation '192.168.10.100', '255.255.255.0', '192.168.10.1'
9
+
10
+ # change the settings obj
11
+ con.ip4_manual = ip4
12
+
13
+ # take minor important device no.2 :)
14
+ dev = NetworkManager.devices[1]
15
+
16
+ # apply the settings obj to the dev
17
+ NetworkManager::DBus::Root.activate_connection con, dev
@@ -3,5 +3,5 @@ require File.join(File.expand_path(File.dirname(__FILE__)), '../lib/network_mana
3
3
  puts "Internet Connection: #{NetworkManager.internet_connection? ? 'yes' : 'no'}"
4
4
 
5
5
  puts "States are described as NM_STATE_... in NetworkManager::DBus::Root"
6
- puts "State is == #{NetworkManager::DBus::Root.instance.object.state}"
6
+ puts "State is == #{NetworkManager::DBus::Root.instance.call('state'}"
7
7
 
@@ -1,21 +1,30 @@
1
1
  module DBusInterface
2
+ class UnavailableError < StandardError; end
3
+
4
+ class Configuration
5
+ attr_accessor :interface
6
+ end
7
+
2
8
  require 'dbus'
9
+ require File.join(File.dirname(__FILE__), 'dbus_interface/connection')
3
10
  require File.join(File.dirname(__FILE__), 'dbus_interface/class')
4
11
  require File.join(File.dirname(__FILE__), 'dbus_interface/object')
5
12
 
6
13
  def self.system_bus
7
14
  ::DBus::SystemBus.instance
15
+ rescue Errno::ENOENT => e
16
+ raise UnavailableError.new "DBus SystemBus not available! (#{e})"
8
17
  end
9
18
 
10
19
  def self.service
11
- @@service
20
+ @@service ||= system_bus.service config.interface
12
21
  end
13
22
 
14
- def self.service=(s)
15
- @@service = system_bus.service s
23
+ def self.configure(&block)
24
+ yield config
16
25
  end
17
26
 
18
- def self.configure(&block)
19
- yield self
27
+ def self.config
28
+ @@config ||= Configuration.new
20
29
  end
21
30
  end
@@ -2,14 +2,22 @@ module DBusInterface::Class
2
2
  def map_dbus(conf)
3
3
  @dbus ||= begin
4
4
  # ensure hash
5
- raise ArgumentError.new "adapt_dbus must receive a hash instead of"\
5
+ raise ArgumentError.new "map_dbus must receive a Hash instead of "\
6
6
  "#{conf.class}" unless conf.is_a? Hash
7
7
  # ensure :default_iface is set
8
- raise ArgumentError.new "adapt_dbus must specify at least :default_iface"\
8
+ raise ArgumentError.new "map_dbus must specify at least :default_iface"\
9
9
  unless conf.has_key? :default_iface
10
10
  conf
11
11
  end
12
12
  end
13
+
14
+ def no_properties!
15
+ @no_properties = true
16
+ end
17
+
18
+ def no_properties?
19
+ defined?(@no_properties) && @no_properties ? true : false
20
+ end
13
21
 
14
22
  def default_iface
15
23
  dbus[:default_iface]
@@ -23,10 +31,26 @@ module DBusInterface::Class
23
31
  def instance
24
32
  @instance ||= new
25
33
  end
26
-
34
+
35
+ def property(name, type = :string)
36
+ underscored = underscore(name)
37
+ define_method underscored do self[name] end
38
+ if type == :boolean
39
+ define_method "#{underscored}?" do self[name] ? true : false end
40
+ end
41
+ end
42
+
27
43
  private
28
44
 
29
45
  def dbus
30
46
  @dbus
31
47
  end
32
- end
48
+
49
+ def underscore(camel_cased_word)
50
+ camel_cased_word.to_s.gsub(/::/, '/').
51
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
52
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
53
+ tr("-", "_").
54
+ downcase
55
+ end
56
+ end
@@ -0,0 +1,58 @@
1
+ class DBusInterface::Connection
2
+ attr_reader :default_iface, :object_path
3
+
4
+ def initialize(default_iface, object_path)
5
+ @default_iface = default_iface
6
+ @object_path = object_path
7
+ end
8
+
9
+ def self.clear!
10
+ connections.clear
11
+ end
12
+
13
+ def self.connections
14
+ @@connections ||= {}
15
+ end
16
+
17
+ def self.add_connection(con)
18
+ @@connections[con.key] = con
19
+ end
20
+
21
+ def self.instance_for(default_iface, object_path)
22
+ con_key = connection_key(default_iface, object_path)
23
+ if connections[con_key]
24
+ connections[con_key]
25
+ else
26
+ new_con = new(default_iface, object_path)
27
+ add_connection(new_con)
28
+ end
29
+ end
30
+
31
+ def self.connection_key(default_iface, object_path)
32
+ [default_iface,object_path].join
33
+ end
34
+
35
+ def key
36
+ self.class.connection_key(default_iface, object_path)
37
+ end
38
+
39
+ def self.call(default_iface, object_path, method, *args)
40
+ con = instance_for(default_iface, object_path)
41
+ con.call(method, *args)
42
+ end
43
+
44
+ def call(method, *args)
45
+ dbus.send(method, *args)
46
+ end
47
+
48
+ private
49
+
50
+ def dbus
51
+ @dbus ||= begin
52
+ d = DBusInterface.service.object(object_path)
53
+ d.default_iface = default_iface
54
+ d.introspect
55
+ d
56
+ end
57
+ end
58
+ end
@@ -3,17 +3,20 @@ module DBusInterface::Object
3
3
  some_base.extend(DBusInterface::Class)
4
4
  end
5
5
 
6
- def object
7
- @object ||= begin
8
- object = DBusInterface.service.object(object_path)
9
- object.default_iface = self.class.default_iface
10
- object.introspect
11
- object
6
+ def call(method, *args)
7
+ if object_path == nil || object_path == '/'
8
+ nil
9
+ else
10
+ DBusInterface::Connection.call(self.class.default_iface, object_path, method, *args)
12
11
  end
13
12
  end
14
13
 
15
14
  def properties
16
- object.all_properties
15
+ if self.class.no_properties?
16
+ nil
17
+ else
18
+ call('all_properties')
19
+ end
17
20
  end
18
21
 
19
22
  def initialize(object_path = nil)
@@ -32,4 +35,9 @@ module DBusInterface::Object
32
35
  def [](key)
33
36
  properties[key]
34
37
  end
38
+
39
+ def to_s
40
+ "#{self.class} #{properties}"
41
+ end
42
+
35
43
  end
@@ -1,5 +1,6 @@
1
1
  # This Library provides an API based on the specs for network manager dbus api
2
2
  # found here: http://projects.gnome.org/NetworkManager/developers/api/09/spec.html
3
+ require 'ipaddress'
3
4
  module NetworkManager
4
5
  # generic dbus api
5
6
  require File.join(File.dirname(__FILE__), 'dbus_interface')
@@ -8,7 +9,7 @@ module NetworkManager
8
9
  require File.join(File.dirname(__FILE__), 'network_manager/version')
9
10
 
10
11
  # helper
11
- require File.join(File.dirname(__FILE__), 'network_manager/ip4_helper')
12
+ require File.join(File.dirname(__FILE__), 'network_manager/ip4_config')
12
13
 
13
14
  # network manager dbus api
14
15
  require File.join(File.dirname(__FILE__), 'network_manager/dbus')
@@ -23,6 +24,6 @@ module NetworkManager
23
24
  end
24
25
 
25
26
  DBusInterface.configure do |config|
26
- config.service = 'org.freedesktop.NetworkManager'
27
+ config.interface = 'org.freedesktop.NetworkManager'
27
28
  end
28
29
  end
@@ -1,4 +1,6 @@
1
1
  module NetworkManager::DBus
2
+ NULL_OBJECT = '/'
3
+
2
4
  # require all .rb files from lib/network_manager/dbus
3
5
  Dir.glob(File.join(File.dirname(__FILE__), "dbus/*.rb")).each do |p|
4
6
  require p
@@ -24,26 +24,28 @@ class NetworkManager::DBus::Device
24
24
  # or LTE standards to access a cellular or wireline data network.
25
25
  NM_DEVICE_TYPE_MODEM = 8
26
26
 
27
- def to_s
28
- "#{self.class} #{properties}"
29
- end
30
-
31
27
  def ip4_address
32
28
  @ip_addr ||= begin
33
29
  ip4_int = self['Ip4Address']
34
- NetworkManager::Ip4Helper.ip4_integer_to_dot_decimal ip4_int
30
+ i = NetworkManager::Ip4Config.from_nm_au ip4_int
31
+ i.address
35
32
  end
36
33
  end
37
34
 
38
35
  # @return [NetworkManager::DBus::Ip4Config] conf
39
36
  def ip4_config
40
- @ip4_config ||= NetworkManager::DBus::Ip4Config.new properties['Ip4Config']
37
+ @ip4_config ||= NetworkManager::DBus::Ip4Config.new self['Ip4Config']
38
+ end
39
+
40
+ # @return [NetworkManager::DBus::Ip4Config] conf
41
+ def dhcp4_config
42
+ @dhcp4_config ||= NetworkManager::DBus::Dhcp4Config.new self['Dhcp4Config']
41
43
  end
42
44
 
43
45
  # @return [NetworkManager::DBus::ActiveConnection] con
44
46
  def active_connection
45
47
  @active_connection ||=
46
- NetworkManager::DBus::ActiveConnection.new properties['ActiveConnection']
48
+ NetworkManager::DBus::ActiveConnection.new self['ActiveConnection']
47
49
  end
48
50
 
49
51
  #
@@ -2,7 +2,7 @@ class NetworkManager::DBus::Root
2
2
  include DBusInterface::Object
3
3
  map_dbus :default_iface => 'org.freedesktop.NetworkManager',
4
4
  :object_path => '/org/freedesktop/NetworkManager'
5
-
5
+
6
6
  # Networking state is unknown.
7
7
  NM_STATE_UNKNOWN = 0
8
8
  # Networking is inactive and all devices are disabled.
@@ -22,20 +22,24 @@ class NetworkManager::DBus::Root
22
22
 
23
23
  # @return [Array<NetworkManager::DBus::Device>]] devices
24
24
  def self.devices
25
- instance.object.GetDevices.map do |list|
25
+ instance.call('GetDevices').map do |list|
26
26
  list.map do |object_path|
27
27
  new_device(object_path)
28
28
  end
29
29
  end.flatten
30
30
  end
31
31
 
32
+ def self.activate_connection(con, dev, optional = NetworkManager::DBus::NULL_OBJECT)
33
+ instance.call('ActivateConnection', con.object_path, dev.object_path, optional)
34
+ end
35
+
32
36
  def self.device_by_interface(interface)
33
- paths = instance.object.GetDeviceByIpIface(interface)
37
+ paths = instance.call('GetDeviceByIpIface', interface)
34
38
  paths.empty? ? nil : new_device(paths.first)
35
39
  end
36
40
 
37
41
  def self.internet_connection?
38
- instance.object.state.first == NM_STATE_CONNECTED_GLOBAL
42
+ instance.call('state').first == NM_STATE_CONNECTED_GLOBAL
39
43
  end
40
44
 
41
45
  private
@@ -3,19 +3,32 @@ class NetworkManager::DBus::Settings
3
3
  map_dbus :default_iface => 'org.freedesktop.NetworkManager.Settings',
4
4
  :object_path => '/org/freedesktop/NetworkManager/Settings'
5
5
 
6
+ # TODO methods
7
+ # GetConnectionByUuid
8
+
9
+ # TODO signals
10
+ # PropertiesChanged
11
+
12
+ property 'Hostname'
13
+ property 'CanModify', :boolean
14
+
6
15
  def self.connections
7
- instance.object.ListConnections.map do |list|
16
+ instance.connections
17
+ end
18
+
19
+ def connections
20
+ call('ListConnections').map do |list|
8
21
  list.map do |object_path|
9
22
  ::NetworkManager::DBus::SettingsConnection.new(object_path)
10
23
  end
11
24
  end.flatten
12
25
  end
13
26
 
14
- def hostname=(new_name)
15
- object.SaveHostname(new_name)
27
+ def add_connection(connection_hash)
28
+ call('AddConnection', connection_hash)
16
29
  end
17
30
 
18
- def hostname
19
- properties['Hostname']
31
+ def hostname=(new_name)
32
+ call('SaveHostname', new_name)
20
33
  end
21
34
  end