networkmanager-dbus 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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