summaryrefslogtreecommitdiff
path: root/README.md
blob: fd96c86a5793a359219ab2ef450e4cdf4d44f3f5 (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
154
155
156
157
158
159
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
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
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
#VyRoute

A python library for VyOS routing service setting

Author:Hochikong  
Contact me:1097225749@qq.com(usually use) or michellehzg@gmail.com(Inconvenient in China mainland)  

This python library is used for VyOS routing service configuration,now it only provide static,RIP and 
OSPF configuration function,I will add BGP function if necessary.If you are interested in this project,you can clone and add features you
want,such as BGP and interfaces setting.

I will continue develop other libraries used for firewall and VPN service configuration.

##Comment
This lib relies on Exscript,you can find it on github.  

MIT opensource license applies to whole library.  

##Requirement
Exscript

##Design
Now,SDN is a technologies trend.Like Openflow and switch controller,they provide us with centralized control and programmable features.But adminstrators of VyOS still need to login the system and 
configure services manually.I need a tool which can configure router service remotely and user can write a program to control the system like SDN controller.So I decide to write this library.Up to now,it just provide static,RIP and OSPF router configuration function.

There are two classes in library:Router and BasicRouter.Router is a parent class,BasicRouter inherit parent class and rewrite its memeber 
methods.When we use this library,we should use VyOS's address and user information to initialize a BasicRouter,then we can use member methods to control the system.
Just like administrators configure services,in this lib you also need to enter configure mode,execute configuration,commit it and save it.

BasicRouter has a member variable(python dictionary) "status",it store a router substance's status.

	self.__status = {"object": None, "commit": None, "save": None, "configure": None}

When it finish initialization,all values in "status" are None.When a 
user login the substance,the value of "object" will change to "login".When the user execute configure(),he will enter configure mode and value of "configure" will change to "Yes",during configure mode,all configuration method will change the value of "commit" and "save" to "no",when user finish a operation but not commit,the following method will not change the value of "commit" and "save".  

When the user want to exit configure mode,only he have commit and save the configuration can he exit configure mode,the value of "commit" and "save" must change to "Yes".If he don't want to save the configuration,he should use exit_config(force=True) to exit.If the user execute logout(),"object" will change to "logout" and the others will change to None.  

When the user enter configure mode,he can use some methods to set up a router.But most of methods should use a configuration data as an input parameter.A configuration data is a python dictionary which include keys and values. Every method will return a result data,similar to the method's input.

	>>> data = {'config':'std'}
	>>> vyos1.delete_route(data)
	{'Error': 'Nonsupport protocols type.'}

Therefore most of methods only have one "data" parameter,but different methods' input data are different.If input data have any mistakes,due to Exscript,the method will return a timeout exception 
after few seconds,then the error reason(from VyOS) will be return when you execute next configuration.So you should execute the former configuration one more time.

	>>> vyos1.delete_route({'config':'all'})
	{'Error': InvalidCommandException('Device said:\nset protocols ospf default-information originate always\r\nWARNING: terminal is not fully functional\r\n\r-  (press RETURN)\r\r\r\x07\x1b[m\r\n  Configuration path: [protocols ospf default-information originate always] already exists\x1b[m\r\n\x1b[m\r\n\r[edit]\r\r\nvyos@vyos# elete protocols\r\n\r\n  Invalid command: [elete]\r\n\r\n[edit]\r\r\nvyos@vyos# ',)}
	>>> vyos1.delete_route({'config':'all'})
	{'Result': 'Delete successfully.'}

In this library,if methods return a information without any mistakes,it doesn't means your configuration is proper(an available router) and it only means your input data is valid.

###Correct:

	>>> vyos1.login()
	{'Result': 'Login successfully.'}

###Error:

	>>> data = {'config':'std'}
	>>> vyos1.delete_route(data)
	{'Error': 'Nonsupport protocols type.'}

In the return of all methods,if it configures successfully,the key of return is "Result".If there any mistakes,the key is"Error".The user can judge whether his configuration is vaild or successful by the only key in return.

##Usage example
We can try to execute a static router confinguration but we don't save it

	>>> from vyroute.Router import BasicRouter
	>>> vyos1 = BasicRouter('172.16.77.184','vyos:vyos')
	>>> vyos1.login()
	{'Result': 'Login successfully.'}
	>>> vyos1.status()
	{'commit': None, 'object': 'login', 'configure': None, 'save': None}
	>>> vyos1.configure()
	{'Result': 'Active configure mode successfully.'}
	>>> static = {'config':{'target':'10.20.10.0/24','next-hop':'10.20.10.1','distance':'1'},}
	>>> vyos1.static_route(static)
	{'Result': 'Configured successfully'}
	>>> vyos1.commit_config()
	{'Result': 'Commit successfully.'}
	>>> vyos1.exit_config(force=True)
	{'Result': 'Exit configure mode successfully.'}
	>>> vyos1.status()
	{'commit': None, 'object': 'login', 'configure': 'No', 'save': None}
	>>> vyos1.logout()
	{'Result': 'Logout successfully.'}
	>>> vyos1.status()
	{'commit': None, 'object': 'logout', 'configure': None, 'save': None}

If you reboot VyOS,you will find the configuration disappears.If you regret your actions,you want to configure again and save it,you can use "vyos1" continue your work.

    >>> vyos1.login()
	{'Result': 'Login successfully.'}
	>>> vyos1.status()
	{'commit': None, 'object': 'login', 'configure': None, 'save': None}
	>>> vyos1.static_route(static)
	{'Error': 'You are not in configure mode.'}
	>>> vyos1.configure()
	{'Result': 'Active configure mode successfully.'}
	>>> vyos1.static_route(static)
	{'Result': 'Configured successfully'}
	>>> vyos1.exit_config()
	{'Error': 'You should commit first.'}
	>>> vyos1.commit_config()
	{'Result': 'Commit successfully.'}
	>>> vyos1.exit_config()
	{'Error': 'You should save first.'}
	>>> vyos1.save_config()
	{'Result': 'Save successfully.'}
	>>> vyos1.status()
	{'commit': 'Yes', 'object': 'login', 'configure': 'Yes', 'save': 'Yes'}
	>>> vyos1.exit_config()
	{'Result': 'Exit configure mode successfully.'}
	>>> vyos1.logout()
	{'Result': 'Logout successfully.'}

Now your configuration will be saved.

#All methods
##login():
No input  

Return a dictionary:   
Login successfully:{'Result': 'Login successfully.'}  
Failed:{"Error": "Connect Failed."}  

If there any mistakes,it will return an dictionary and the value is a python exception.(Every method below has this return when an exception rises,so I will ignore this when I explain following methods.)

You should create a router substance then you can use this method to login.

	>>> from vyroute.Router import BasicRouter
	>>> vyos1 = BasicRouter('172.16.77.184','vyos:vyos')
	>>> vyos1.login()
	{'Result': 'Login successfully.'}

##logout()
No input  

Return a dictionary:  
Logout successfully:{"Result": "Logout successfully."}

This method execute a close() on a connection.

You can use this method logout a router substance.

##status()
No input  

Return a dictionary,return the status of router substance.

##configure()
No input  

Return a dictionary:  
Enter configure mode successfully:{"Result": "Active configure mode successfully."}  
If you already in configure mode:{"Error": "In configure mode now!"}  
If you still not login:{"Error": "Router object not connect to a router."}  

You can use this method enter configure mode,but you should login a substance first.

	>>> vyos1.configure()
	{'Result': 'Active configure mode successfully.'}

##commit_config()
No input  

Return a dictionary:  
Commit successfully:{"Result": "Commit successfully."}  
If "commit" is None:{"Error": "You don't need to commit."}  
If you have commit before:{"Error": "You have committed!"}  
If you are not in configure mode:{"Error": "Router not in configure mode!"}  
If you still not login:{"Error": "Router object not connect to a router."}  

Every methods below will check whether you have login and enter configure mod,if not it will return a error info and you can read the content of return from here.I will ignore these return when I explain following methods.

You can use this method to commit your configuration.

	>>> vyos1.commit_config()
	{'Result': 'Commit successfully.'}

##save_config()
No input  

Return a dictionary:
Save successfully:{"Result": "Save successfully."}  
If "save" is None:{"Error": "You don't need to save."}  
If you have save before:{"Error": "You have saved!"}  
If you still not commit:{"Error": "You need to commit first!"}  

You can use this method to save your configuration.

	>>> vyos1.save_config()
	{'Result': 'Save successfully.'}

##exit_config(force=False)
Parameter "force":  
True or False.The default value is False,if you don't want to save your configuration you should use "force=True" as input.

Return a dictionary:  
Exit successfully:{"Result": "Exit configure mode successfully."}  

If you do not commit and save,please read the 6th explanation to get more infomation.

##lo(data)
Parameter "data":a dictionary  
Example:{'config':'1.1.1.1/32'}  

Return a dictionary:  
Configure successfully:{"Result": "Modify successfully."}  

You can use this method to create a new VyOS loopback address for interface "lo".We usually use this new address as router id.

##delete_route(data)
Parameter "data":a dictionary  
Example:{'config':'all'}

The value of "config" just "rip","static","ospf" and "all".Please remember "all" will delete all configuration in the section "protocols" in VyOS's configuration file.The others will delete the corresponding part of configuration in "protocols" section.

Return a dictionary:  
Delete successfully:{"Result": "Delete successfully."}  
Invalid value:{"Error": "Nonsupport protocols type."}  

You can use this method delete router configuration but please be careful.

##static_route(data)
Parameter "data":a dictionary  
Example:{'config':{'target':'10.20.10.0/24','next-hop':'10.20.10.1','distance':'1'},}  

This method equal to "set protocols static route next-hop distance".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"}

You can use this method configure a static router.

##rip_route(data)
Parameter "data":a dictionary  
Example:{'config':'192.168.10.0/24',}  

This method equal to "set protocols rip network" and "set protocols rip redistribute connected".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"}  

You can use this method configure a RIP router and execute routing redistribution.

##ospf_area(data)
Parameter "data":a dictionary  
Example:{'config':{'area':'0','network':'192.168.10.0/24'},}  

This method equal to "set protocols ospf area network".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"}  

You can use this method configure OSPF areas.

##router_id(data)
Parameter "data":a dictionary  
Example:{'config':{'id':'1.1.1.1'},}  

This method equal to "set protocols ospf parameters router-id".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"}

You can use this method configure router id.

##ospf_redistribute(data)
Parameter "data":a dictionary  
Example: {'config':{'type':'2'},}  

This method equal to "set protocols ospf redistribute connected metric-type" and "set protocols ospf redistribute connected route-map CONNECT".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"}  

You can use this method execute routing redistribution.

##ospf_adjacency()
No input

This method equal to "set protocols ospf log-adjacency-changes".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"}

##ospf\_default\_route(data)
Parameter "data":a dictionary  
Example:{'config':{'metric':'10','metric-type':'2'},}  

This method equal to "set protocols ospf default-information originate always","set protocols ospf default-information originate metric" and "set protocols ospf default-information originate metric-type".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"}  

You can use this method configure default route.

##ospf\_route\_map(data)
Parameter "data":a dictionary  
Example:{'config':{'rule':'10','interface':'lo'},}  

This method equal to "set policy route-map CONNECT rule action permit" and "set policy route-map CONNECT rule match interface".

Return a dictionary:  
Configure successfully:{"Result": "Configured successfully"} 

You can use this method configure route-map.

==================================================================================

# VyRoute
一个用于VyOS路由服务设置的库

作者:Hochikong  
联系我:michellehzg@gmail.com(较少用) or 1097225749@qq.com

这是一个用于设置VyOS路由功能的Python库,目前仅仅提供了静态路由,RIP和OSPF的功能,以后有需要会增加BGP的部分,如果你有兴趣,可以试着clone一份增加你想要的功能,比如BGP和网络接口设置。

在后面我还会继续开发实现VyOS的防火墙、VPN配置的库。

##备注
已经打包好的egg文件在:[https://github.com/Hochikong/vyroute/tree/master/dist](https://github.com/Hochikong/vyroute/tree/master/dist)  

可以下载并用easy_install安装egg包

下面我会给出这个库的使用说明和注意事项:

本库依赖于Exscript库,可以在github上找到

本库基于MIT协议开源

##设计
这个库主要是为了可编程、满足远程管理VyOS路由功能的需求而编写,目前实现了RIP、静态、OSPF三种AS内部协议配置的功能。  

库中只有两个类,Router和BasicRouter类,BasicRouter继承Router并重写成员方法。当我们使用这个库时,传入具体的VyOS路由的地址、用户名和相应的密码以实例化BasicRouter类,然后我们就可以通过类的成员方法对路由器进行远程控制

和管理员手动操作VyOS一样,首先要登陆VyOS并进入configure模式才能进行配置,配置完毕后要提交并保存才退出管理。

类中有一个status的成员变量,为一个python字典,记录着该路由实例的状态:

	self.__status = {"object": None, "commit": None, "save": None, "configure": None}

在一开始实例化时,所有状态都为none,当用户执行login后,object会变为“login”状态,进入configure模式后,configure会变为“Yes”状态。期间任何对路由实例的配置操作都会把commit和save的状态改为“No”,不过如果前面有尚未提交的修改,后续的修改并不会再次改写commit和save的状态,而是保持“No”。一旦用户打算退出configure模式,如果不加入强制退出的参数,则会检查commit和save的状态,确保两个状态都变为“Yes”才允许退出。如果用户执行logout,所有状态都会变为None,而object会变为“logout”

在用户进入configure模式后,就可以着手配置相关的路由功能,比如设置静态路由等,大部分函数都要输入数据进行配置,在这里我用的是一个python字典作为数据载体,返回的结果也以字典为载体:

	>>> data = {'config':'std'}
	>>> vyos1.delete_route(data)
	{'Error': 'Nonsupport protocols type.'}

因此绝大多数的函数都只有一个data参数,但是各种data的格式是不同的,用户需要按照下面我提供的说明输入才能正确配置,如果数据有错误,由于Exscript的问题,执行函数后会很迟才返回一个超时Error,然后在你执行下个命令时会把前面的错误的原因返回(VyOS返回的错误原因),此时你需要把刚刚的命令再执行一遍:

	>>> vyos1.delete_route({'config':'all'})
	{'Error': InvalidCommandException('Device said:\nset protocols ospf default-information originate always\r\nWARNING: terminal is not fully functional\r\n\r-  (press RETURN)\r\r\r\x07\x1b[m\r\n  Configuration path: [protocols ospf default-information originate always] already exists\x1b[m\r\n\x1b[m\r\n\r[edit]\r\r\nvyos@vyos# elete protocols\r\n\r\n  Invalid command: [elete]\r\n\r\n[edit]\r\r\nvyos@vyos# ',)}
	>>> vyos1.delete_route({'config':'all'})
	{'Result': 'Delete successfully.'}


在这个库中,如果配置成功(不返回错误,但不意味着你配置一定可以起作用,比如你把静态路由的下一跳设错地址,虽然VyOS不会提示你错,但是的确是用不了的)会返回一个字典,键为“Result”,如果是错误则为“Error”:

错误:

	>>> data = {'config':'std'}
	>>> vyos1.delete_route(data)
	{'Error': 'Nonsupport protocols type.'}

正确:

	>>> vyos1.login()
	{'Result': 'Login successfully.'}

当用户使用这个库进行高级开发时可以单单靠结果的键判断是否成功。


#函数解释
##login():  
没有任何参数
  
返回一个字典:  
登陆成功:{'Result': 'Login successfully.'}  
失败:{"Error": "Connect Failed."}  
如果是其他错误则会返回一个字典,其值为相关的python异常

用户使用这个登陆实例化的路由对象,前提是你已经实例化一个路由:

	>>> from vyroute.Router import BasicRouter
	>>> vyos1 = BasicRouter('172.16.77.184','vyos:vyos')
	>>> vyos1.login()
	{'Result': 'Login successfully.'}

##logout()
没有任何参数

返回一个字典:   
退出成功:{"Result": "Logout successfully."}   
如果是其他错误则会返回一个字典,其值为相关的python异常(后面每个函数都有这个,不再重复)  

用户使用这个退出一个路由实例,即close()一个连接:

	>>> vyos1.logout()
	{'Result': 'Logout successfully.'}

##status()
没有任何参数

返回一个字典,返回实例的内部状态

##configure()
没有任何参数

返回一个字典:  
进入成功:{"Result": "Active configure mode successfully."}  
如果你已经在configure模式:{"Error": "In configure mode now!"}  
如果你没有login:{"Error": "Router object not connect to a router."}(后面每个函数都会检查这个,本文档不再重复此部分)

用户使用这个进入configure模式,前提是你已经登入VyOS实例:

	>>> vyos1.configure()
	{'Result': 'Active configure mode successfully.'}


##commit_config()	
没有任何参数  

返回一个字典:  
提交成功:{"Result": "Commit successfully."}  
如果commit为None:{"Error": "You don't need to commit."}  
如果你已经提交过一次:{"Error": "You have committed!"}  
没在configure模式:{"Error": "Router not in configure mode!"}(后面的都会检查,不再重复)

用户使用这个提交配置,前提是你已经在configure模式:

	>>> vyos1.commit_config()
	{'Result': 'Commit successfully.'}

##save_config()
没有任何参数

返回一个字典:  
保存成功:{"Result": "Save successfully."}  
如果save状态为none:{"Error": "You don't need to save."}  
如果已经保存:{"Error": "You have saved!"}  
如果没提交:{"Error": "You need to commit first!"}  

用户用这个来保存配置,前提是你已经提交:

	>>> vyos1.save_config()
	{'Result': 'Save successfully.'}

##exit_config(force=False)
参数force:布尔值True或者False,默认为False,如果force为真,则不管是否已经提交和保存都退出,为假则要求先提交再保存才能退出

返回一个字典:  
退出成功:{"Result": "Exit configure mode successfully."}  
没提交、没保存的返回请参考前面

用户用这个退出configure模式,前提是你在configure模式

##lo(data)  
参数data:字典数据  
数据范例:{'config':'1.1.1.1/32'}

返回一个字典:  
配置成功:{"Result": "Modify successfully."}

用户用这个创建VyOS loopback接口lo的一个新地址(不能修改默认值,与新地址共存),通常用这个地址(除去掩码)作为路由ID

##delete_route(data)
参数data:字典数据  
数据范例:{'config':'rip'/'static'/'ospf'/'all'}  
config的值仅可以为rip、static、ospf和all,all将会删除VyOS中protocols的全部内容,而其他参数会删除对应协议的全部配置内容。因为VyOS中部分条件相同的新设置可以覆盖原有的设置,建议修改某个错误的设置时要用回更正后的原命令修改。

返回一个字典:  
删除成功:{"Result": "Delete successfully."}  
不支持的config值:{"Error": "Nonsupport protocols type."}

用户用这个删除不想要的路由配置内容,但是要慎重使用

##static_route(data)
参数data:字典数据  
数据范例:{'config':{'target':'10.20.10.0/24','next-hop':'10.20.10.1','distance':'1'},}  
这个函数相当于执行set protocols static route next-hop distance

返回一个字典:  
配置成功:{"Result": "Configured successfully"}  

用户用这个设置静态路由,这是静态路由设置的基础

##rip_route(data)
参数data:字典数据  
数据范例:{'config':'192.168.10.0/24',}  
这个函数相当于执行set protocols rip network和set protocols rip redistribute connected

返回一个字典:  
{"Result": "Configured successfully"}

用户用这个来设置RIP协议的路由,执行宣告网络范围和路由重发布

##ospf_area(data)
参数data:字典数据  
数据范例:{'config':{'area':'0','network':'192.168.10.0/24'},}  
这个函数相当于执行set protocols ospf area network

返回一个字典:
{"Result": "Configured successfully"}

用户用这个来设置OSPF区域和相应的网络

##router_id(data)
参数data:字典数据  
数据范例:{'config':{'id':'1.1.1.1'},}  
这个函数相当于执行set protocols ospf parameters router-id

返回一个字典:  
{"Result": "Configured successfully"}

用户用这个设置路由ID,可以用新增的lo地址去掉掩码来当ID

##ospf_redistribute(data)
参数data:字典数据  
数据范例: {'config':{'type':'2'},}  
这个函数相当于执行set protocols ospf redistribute connected metric-type和set protocols ospf redistribute connected route-map CONNECT

返回一个字典:  
{"Result": "Configured successfully"}

用户用这个来进行路由重发布

##ospf_adjacency()
没有任何参数  
这个函数相当于执行set protocols ospf log-adjacency-changes

返回一个字典:  
{"Result": "Configured successfully"}

用户用这个激活路由协议邻接关系变化日志功能

##ospf\_default\_route(data)
参数data:字典数据  
数据范例:{'config':{'metric':'10','metric-type':'2'},}  
这个函数相当于执行set protocols ospf default-information originate always、set protocols ospf default-information originate metric和set protocols ospf default-information originate metric-type

返回一个字典:  
{"Result": "Configured successfully"}

用户用这个发布默认路由

##ospf\_route\_map(data)
参数data:字典数据
数据范例:{'config':{'rule':'10','interface':'lo'},}  
这个函数相当于执行set policy route-map CONNECT rule action permit和set policy route-map CONNECT rule match interface

返回一个字典:  
{"Result": "Configured successfully"}

用户用这个来设置route-map