回答編集履歴
2
誤記修正
test
CHANGED
@@ -60,7 +60,7 @@
|
|
60
60
|
|
61
61
|
# ファイルを何かが開いていたら厄介なので、一旦テンポラリにコピーする
|
62
62
|
|
63
|
-
yl
|
63
|
+
yield collect(os.path.join(root, file))
|
64
64
|
|
65
65
|
|
66
66
|
|
1
追記
test
CHANGED
@@ -345,3 +345,295 @@
|
|
345
345
|
main()
|
346
346
|
|
347
347
|
```
|
348
|
+
|
349
|
+
|
350
|
+
|
351
|
+
---
|
352
|
+
|
353
|
+
(2015/06/28追記)
|
354
|
+
|
355
|
+
|
356
|
+
|
357
|
+
ssh(sftp)経由でリモートのパスを舐め、ファイルを取得してくるように改変します。
|
358
|
+
|
359
|
+
その前に、サードパーティのモジュールをインストールします。
|
360
|
+
|
361
|
+
|
362
|
+
|
363
|
+
```lang-sh
|
364
|
+
|
365
|
+
pip install paramiko
|
366
|
+
|
367
|
+
```
|
368
|
+
|
369
|
+
※paramikoのインストールには色々と厄介なことがあるようです。linuxでは起こりにくいとは思いますが、ハッシュ化や暗号化モジュールがうまく入らない場合、また情報をください。
|
370
|
+
|
371
|
+
|
372
|
+
|
373
|
+
sshでファイルを収集するプログラムは次のような感じでできます。
|
374
|
+
|
375
|
+
ssh経由でファイルを探す部分は手作りですね。walkを適当に拾ったのを参考に自作しました。(黒)
|
376
|
+
|
377
|
+
1件だけ懸念点があり、SHHで接続に失敗する場合、直接鍵ファイルを指定する必要があるかもしれません。
|
378
|
+
|
379
|
+
|
380
|
+
|
381
|
+
コメントにしている、以下のコードを有効にし、鍵ファイルへのパスを直接指定してください。
|
382
|
+
|
383
|
+
conn.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
|
384
|
+
|
385
|
+
|
386
|
+
|
387
|
+
以下、対象ホストSSH接続し、ファイルを収集、内容をデータベースに書き出すサンプルです。
|
388
|
+
|
389
|
+
データベースのテーブル定義などは考慮していません。適時修正ください。
|
390
|
+
|
391
|
+
|
392
|
+
|
393
|
+
```lang-python
|
394
|
+
|
395
|
+
# -*- coding: utf-8 -*-
|
396
|
+
|
397
|
+
|
398
|
+
|
399
|
+
import re
|
400
|
+
|
401
|
+
import os
|
402
|
+
|
403
|
+
from tempfile import mkdtemp
|
404
|
+
|
405
|
+
|
406
|
+
|
407
|
+
import paramiko
|
408
|
+
|
409
|
+
from stat import S_ISDIR
|
410
|
+
|
411
|
+
|
412
|
+
|
413
|
+
from sqlalchemy import create_engine
|
414
|
+
|
415
|
+
from sqlalchemy.orm import sessionmaker
|
416
|
+
|
417
|
+
from sqlalchemy.ext.declarative import declarative_base
|
418
|
+
|
419
|
+
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, Sequence
|
420
|
+
|
421
|
+
|
422
|
+
|
423
|
+
HOST_ADDRESS = "XX.XX.XX.XX" #データ収集時の接続先ホストIPアドレス
|
424
|
+
|
425
|
+
SSH_PORT = 22 #SSH接続ポート
|
426
|
+
|
427
|
+
SSH_PASSWORD = "XXXXXXXX" #SSH接続パスワード
|
428
|
+
|
429
|
+
SSH_USERNAME = "wheeluser" #SHH接続ユーザ名
|
430
|
+
|
431
|
+
|
432
|
+
|
433
|
+
FILENAME_PATTERN = '20150601' #収集対象とするファイル名のパターン
|
434
|
+
|
435
|
+
ROOT_PATH = r'/home/username/' #収集するファイルが存在するトップディレクトリ
|
436
|
+
|
437
|
+
CONNECT_STRING = 'mysql://<ユーザ名>:<パスワード>@<ip>/<db名>' #DB接続文字列
|
438
|
+
|
439
|
+
|
440
|
+
|
441
|
+
# ローカルがwindows機である場合、os.path.joinのパスのデリミタで問題がでるのでその対処
|
442
|
+
|
443
|
+
RELATIONSHIP_TO_HOST = "posix_to_posix" # "posix_to_posix" / "nt_to_posix" / "posix_to_nt"
|
444
|
+
|
445
|
+
|
446
|
+
|
447
|
+
if RELATIONSHIP_TO_HOST == "posix_to_posix":
|
448
|
+
|
449
|
+
from os import path as remote_path
|
450
|
+
|
451
|
+
elif RELATIONSHIP_TO_HOST == "nt_to_posix":
|
452
|
+
|
453
|
+
import posixpath as remote_path
|
454
|
+
|
455
|
+
elif RELATIONSHIP_TO_HOST == "posix_to_nt":
|
456
|
+
|
457
|
+
import ntpath as remote_path
|
458
|
+
|
459
|
+
|
460
|
+
|
461
|
+
import logging
|
462
|
+
|
463
|
+
from datetime import datetime
|
464
|
+
|
465
|
+
logging.basicConfig(filename=datetime.today().strftime(r"%Y%m%d_%H%M%S")+'.log', level=logging.DEBUG)
|
466
|
+
|
467
|
+
|
468
|
+
|
469
|
+
r = re.compile("[a-zA-Z]+-(?P<date>\d{8})\.txt") #対象ファイル名を示す正規表現を定義。
|
470
|
+
|
471
|
+
|
472
|
+
|
473
|
+
Base = declarative_base()
|
474
|
+
|
475
|
+
|
476
|
+
|
477
|
+
class Data(Base):
|
478
|
+
|
479
|
+
__tablename__ = 'tablename'
|
480
|
+
|
481
|
+
id = Column('id', Integer, Sequence('id_seq'), primary_key=True)
|
482
|
+
|
483
|
+
somedata = Column('somedata', String(512))
|
484
|
+
|
485
|
+
|
486
|
+
|
487
|
+
def __init__(self, somedata):
|
488
|
+
|
489
|
+
self.somedata = somedata
|
490
|
+
|
491
|
+
def __repr__(self):
|
492
|
+
|
493
|
+
return "<Data('%s',...)>" % (self.somedata)
|
494
|
+
|
495
|
+
|
496
|
+
|
497
|
+
|
498
|
+
|
499
|
+
def walk(sftp, path):
|
500
|
+
|
501
|
+
current = path
|
502
|
+
|
503
|
+
files = []
|
504
|
+
|
505
|
+
folders = []
|
506
|
+
|
507
|
+
for item in sftp.listdir_attr(current):
|
508
|
+
|
509
|
+
if S_ISDIR(item.st_mode):
|
510
|
+
|
511
|
+
folders.append(item.filename)
|
512
|
+
|
513
|
+
else:
|
514
|
+
|
515
|
+
files.append(item.filename)
|
516
|
+
|
517
|
+
yield current, folders, files
|
518
|
+
|
519
|
+
for folder in folders:
|
520
|
+
|
521
|
+
for x in walk(sftp, remote_path.join(path, folder)):
|
522
|
+
|
523
|
+
yield x
|
524
|
+
|
525
|
+
|
526
|
+
|
527
|
+
def collect(sftp, filename):
|
528
|
+
|
529
|
+
tempdir = mkdtemp()
|
530
|
+
|
531
|
+
dist = os.path.join(tempdir, os.path.basename(filename))
|
532
|
+
|
533
|
+
logging.info("copy file from " + filename + " to " + dist)
|
534
|
+
|
535
|
+
sftp.get(filename, dist, lambda x, y: (logging.warning("File tranceport fail !!!") if x!=y else logging.info("File tranceport success.")))
|
536
|
+
|
537
|
+
return dist
|
538
|
+
|
539
|
+
|
540
|
+
|
541
|
+
def gen_filelist(sftp, path):
|
542
|
+
|
543
|
+
for root, dirs, files in walk(sftp, path):
|
544
|
+
|
545
|
+
for file in files:
|
546
|
+
|
547
|
+
m = r.match(file)
|
548
|
+
|
549
|
+
if(m and FILENAME_PATTERN in m.groupdict().values()):
|
550
|
+
|
551
|
+
# ファイルを何かが開いていたら厄介なので、一旦テンポラリにコピーする
|
552
|
+
|
553
|
+
yield collect(sftp, remote_path.join(root, file))
|
554
|
+
|
555
|
+
|
556
|
+
|
557
|
+
def read_line(data):
|
558
|
+
|
559
|
+
#データを読み出す。例えばcsvファイルをカンマで分けるとか。
|
560
|
+
|
561
|
+
#今回は、ORMのクラスにデータを格納してそのまま返します。
|
562
|
+
|
563
|
+
return Data(data)
|
564
|
+
|
565
|
+
|
566
|
+
|
567
|
+
def read(filename):
|
568
|
+
|
569
|
+
with open(filename, "r") as f:
|
570
|
+
|
571
|
+
lines = []
|
572
|
+
|
573
|
+
for line in f.readlines():
|
574
|
+
|
575
|
+
if(line.strip() != ""):
|
576
|
+
|
577
|
+
lines.append(read_line(line))
|
578
|
+
|
579
|
+
return lines
|
580
|
+
|
581
|
+
|
582
|
+
|
583
|
+
|
584
|
+
|
585
|
+
def main():
|
586
|
+
|
587
|
+
#SQLAlchemyの準備
|
588
|
+
|
589
|
+
engine = create_engine(CONNECT_STRING, encoding='utf-8', echo=True)
|
590
|
+
|
591
|
+
Session = sessionmaker(bind=engine)
|
592
|
+
|
593
|
+
session = Session()
|
594
|
+
|
595
|
+
|
596
|
+
|
597
|
+
#SFTP接続の準備
|
598
|
+
|
599
|
+
conn = paramiko.SSHClient()
|
600
|
+
|
601
|
+
conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
602
|
+
|
603
|
+
#conn.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) #鍵ファイルを直接指定する場合
|
604
|
+
|
605
|
+
conn.connect(HOST_ADDRESS, port=SSH_PORT, password=SSH_PASSWORD, username=SSH_USERNAME)
|
606
|
+
|
607
|
+
sftp = conn.open_sftp()
|
608
|
+
|
609
|
+
|
610
|
+
|
611
|
+
#ファイルの一覧を取得
|
612
|
+
|
613
|
+
files = gen_filelist(sftp, ROOT_PATH)
|
614
|
+
|
615
|
+
|
616
|
+
|
617
|
+
#ファイルの内容を取得
|
618
|
+
|
619
|
+
for file in files:
|
620
|
+
|
621
|
+
data = read(file)
|
622
|
+
|
623
|
+
session.add(data)
|
624
|
+
|
625
|
+
|
626
|
+
|
627
|
+
#データベースへ内容を登録
|
628
|
+
|
629
|
+
session.commit()
|
630
|
+
|
631
|
+
|
632
|
+
|
633
|
+
if __name__ == '__main__':
|
634
|
+
|
635
|
+
main()
|
636
|
+
|
637
|
+
```
|
638
|
+
|
639
|
+
|