반응형
nova 에서 instance 를 생성할 때 호출되는 Sequence 흐름을 표현한다.
모듈별 흐름으로 보면 다음과 같다.
API -> COMPUTE -> RabbitMQ -> SCHEDULER -> RabbitMQ -> COMPUTE
1. api/openstack/servers.py -> create()
1-1. api/openstack/create_instance_helper.py -> create_instance()
- request 로 넘어온 값을 추출
- glance Image 서버에 접근할 수 있는 객체 생성
- glance 로 부터 image id, kernel id, ramdisk id 를 조회
1-1-1. compute/instance_types.py -> get_instance_type_by_flavor_id()
- db로 부터 instance type 을 조회
1-1-2. compute/api.py -> create()
- 넘어온 파라미터에 대한 체크
1-1-2-1. create_db_entry_for_new_instance()
1-1-2-1-1. self.db.security_group_get_by_name()
- db에서 security group name 으로 id를 조회
1-1-2-1-2. self.db.instance_create()
- instance 테이블에 기본 값만 추가하여 instance id 를 생성
1-1-2-1-3. self.db.instance_add_security_group()
- security_group_instance_association 테이블에 값을 추가
1-1-2-1-4. self._update_image_block_device_mapping()
- glance 에서 가져온 image 메타데이터 mappings 정보를 이용
1-1-2-1-4-1. self.db.block_device_mapping_update_or_create()
- 파라미터로 넘어온 mappings 값이 있으면
block_device_mapping 테이블에 저장
1-1-2-1-5. self._update_block_device_mapping()
- glance 에서 가져온 image 메타데이터 block_device_mappings
정보를 이용
1-1-2-1-5-1. self.db.block_device_mapping_update_or_create()
- 파라미터로 넘어온 mappings 값이 있으면
block_device_mapping 테이블에 저장
1-1-2-1-6. self._update_block_device_mapping()
- 파라미터로 넘어온 mappings 정보를 이용
1-1-2-1-6-1. self.db.block_device_mapping_update_or_create()
- 파라미터로 넘어온 mappings 값이 있으면
block_device_mapping 테이블에 저장
1-1-2-1-7. self.update()
1-1-2-1-7-1. self.db.instance_update()
- instances 테이블에 vm_state 와 task_state 값을
BUILDING, SCHEDULING 으로 수정
1-1-2-2. _ask_scheduler_to_create_instance()
1-1-2-2-1. rpc.cast(context,
FLAGS.scheduler_topic,
{"method": "run_instance",
"args": {"topic": FLAGS.compute_topic,
"instance_id": instance_id,
"request_spec": request_spec,
"availability_zone": availability_zone,
"admin_password": admin_password,
"injected_files": injected_files,
"requested_networks": requested_networks}})
- rpc.cast 로 scheduler 의 run_instance 메소드를 호출
- rpc.cast 로 scheduler 의 run_instance 메소드를 호출
2. scheduler/manager.py.SchedulerManager -> __getattr__()
- run_instance 메소드가 없으니 __getattr__ 메소드가 호출됨
2-1. _schedule()
2-1-1. scheduler/multi.py -> __getattr__()
- schedule_run_instance 메소드가 없으니 __getattr__ 메소드가 호출
2-1-1-1. scheduler/chance.py.ChanceScheduler -> schedule_run_instance()
- schedule_run_instance() 가 없어 AttributeError exception 이 발생
2-1-2. scheduler/multi.py -> schedule()
2-1-2-1. scheduler/chance.py.ChanceScheduler -> schedule()
2-1-3. rpc.cast(context,
db.queue_get_for(context, topic, host),
{"method": method,
"args": kwargs})
- rpc.cast 로 compute 의 run_instance 메소드를 호출
3. compute/manager.py.ComputeManager -> run_instance()
3-1. self._run_instance()
3-1-1. self.db.instance_get()
- db 에서 instance 정보를 조회함
3-1-2. virt/libvirt/connection.py.LibvirtConnection -> list_instances()
- libvirt 를 이용하여 kvm 에서 기동중인 instance vm id 를 조회
- instance['name'] 이 kvm 에서 조회되는 vm id 임
3-1-3. self.db.instance_update()
- instances 테이블에 vm_state 와 task_state 를 BUILDING, NETWORKING 으로 변경
- FLAGS.stub_network 이 False 이면
3-1-4-1. self.db.instance_update()
- instances 테이블에 vm_state 와 task_state 를 BUILDING,
BLOCK_DEVICE_MAPPING으로 변경
3-1-5. self._setup_block_device_mapping()
3-1-5-1. self.db.block_device_mapping_get_all_by_instance()
- instances 테이블과 block_device_mapping 테이블을 조인하여 조회
- snapshot_id 값이 있고, volume_id 값이 없으면 아래가 호출됨
3-1-5-2. volume/apy.py.API -> create()
3-1-5-2-1. self.db.snapshot_get()
3-1-5-2-2. quota.py -> allowed_volumes()
3-1-5-2-3. self.db.volume_create()
- volumes 테이블에 추가, status, attach_status 는 creating,
detached 로 세팅
3-1-5-2-4. rpc.cast(context,
- rpc.cast 로 compute 의 run_instance 메소드를 호출
3. compute/manager.py.ComputeManager -> run_instance()
3-1. self._run_instance()
3-1-1. self.db.instance_get()
- db 에서 instance 정보를 조회함
3-1-2. virt/libvirt/connection.py.LibvirtConnection -> list_instances()
- libvirt 를 이용하여 kvm 에서 기동중인 instance vm id 를 조회
- instance['name'] 이 kvm 에서 조회되는 vm id 임
3-1-3. self.db.instance_update()
- instances 테이블에 vm_state 와 task_state 를 BUILDING, NETWORKING 으로 변경
- FLAGS.stub_network 이 False 이면
3-1-3. network/api.py.API -> allocate_for_instance()
3-1-3-1. rpc.call(context, FLAGS.network_topic,
{'method': 'allocate_for_instance',
'args': args})
3-1-4. self._instance_update()3-1-4-1. self.db.instance_update()
- instances 테이블에 vm_state 와 task_state 를 BUILDING,
BLOCK_DEVICE_MAPPING으로 변경
3-1-5. self._setup_block_device_mapping()
3-1-5-1. self.db.block_device_mapping_get_all_by_instance()
- instances 테이블과 block_device_mapping 테이블을 조인하여 조회
- snapshot_id 값이 있고, volume_id 값이 없으면 아래가 호출됨
3-1-5-2. volume/apy.py.API -> create()
3-1-5-2-1. self.db.snapshot_get()
3-1-5-2-2. quota.py -> allowed_volumes()
3-1-5-2-3. self.db.volume_create()
- volumes 테이블에 추가, status, attach_status 는 creating,
detached 로 세팅
3-1-5-2-4. rpc.cast(context,
FLAGS.scheduler_topic,
{"method": "create_volume",
"args": {"topic": FLAGS.volume_topic,
"volume_id": volume['id'],
"snapshot_id": snapshot_id}})
- rpc.cast 로 Volume 을 호출
3-1-5-3. volume/manager.py.VolumeManager -> create_volume()
3-1-5-3-1. self.db.volume_get()
- volumes 테이블 정보 조회
3-1-5-3-2. self.db.volume_update()
- volumes 테이블 host colume 에 떠있는 host 값 저장
- snapshot_id 가 없으면 아래가 호출
3-1-5-3-3. volume.san.py.HpSanISCSIDriver -> create_volume()
- snapshot_id 가 있으면 아래가 호출
3-1-5-3-4. self.db.snapshot_get()
3-1-5-3-5. volume.san.py.HpSanISCSIDriver ->
create_volume_from_snapshot()
- iSCSI 를 노출
3-1-5-3-6. volume.san.py.HpSanISCSIDriver -> create_export()
3-1-5-3-7. self.db.volume_update()
- volumes 테이블의 status, launched_at 을 available,
utils.py -> utcnow() 로 수정
3-1-5-4. volume/apy.py.API -> wait_creation()
- greenthread.sleep(1) 을 호출하여 volumes 테이블의 status 를 체킹
3-1-5-5. self.db.block_device_mapping_update()
- block_device_mapping 테이블의 volume_id 값을 volumes 테이블의 id 로 세팅
3-1-5-6. volume/apy.py.API -> check_attach()
- volumes 테이블을 조회하여 status 가 available 인지 체크
3-1-5-7. self._attach_volume_boot()
3-1-5-7-1. volume/apy.py.API -> check_attach()
3-1-5-7-2. volume/manager.py.VolumeManager -> setup_compute_volume()
- volumes 테이블을 조회하여 host 값이 현재의 host 와 같고
FLAGS.use_local_volumes 값이 True 이면
3-1-5-7-2-1. volume.san.py.HpSanISCSIDriver -> local_path()
- 아니면
3-1-5-7-2-2. volume.driver.py.ISCSIDriver -> discover_volume()
- rpc.cast 로 Volume 을 호출
3-1-5-3. volume/manager.py.VolumeManager -> create_volume()
3-1-5-3-1. self.db.volume_get()
- volumes 테이블 정보 조회
3-1-5-3-2. self.db.volume_update()
- volumes 테이블 host colume 에 떠있는 host 값 저장
- snapshot_id 가 없으면 아래가 호출
3-1-5-3-3. volume.san.py.HpSanISCSIDriver -> create_volume()
- snapshot_id 가 있으면 아래가 호출
3-1-5-3-4. self.db.snapshot_get()
3-1-5-3-5. volume.san.py.HpSanISCSIDriver ->
create_volume_from_snapshot()
- iSCSI 를 노출
3-1-5-3-6. volume.san.py.HpSanISCSIDriver -> create_export()
3-1-5-3-7. self.db.volume_update()
- volumes 테이블의 status, launched_at 을 available,
utils.py -> utcnow() 로 수정
3-1-5-4. volume/apy.py.API -> wait_creation()
- greenthread.sleep(1) 을 호출하여 volumes 테이블의 status 를 체킹
3-1-5-5. self.db.block_device_mapping_update()
- block_device_mapping 테이블의 volume_id 값을 volumes 테이블의 id 로 세팅
3-1-5-6. volume/apy.py.API -> check_attach()
- volumes 테이블을 조회하여 status 가 available 인지 체크
3-1-5-7. self._attach_volume_boot()
3-1-5-7-1. volume/apy.py.API -> check_attach()
3-1-5-7-2. volume/manager.py.VolumeManager -> setup_compute_volume()
- volumes 테이블을 조회하여 host 값이 현재의 host 와 같고
FLAGS.use_local_volumes 값이 True 이면
3-1-5-7-2-1. volume.san.py.HpSanISCSIDriver -> local_path()
- 아니면
3-1-5-7-2-2. volume.driver.py.ISCSIDriver -> discover_volume()
3-1-5-7-2-2-1. self._get_iscsi_properties()
- self._execute('iscsiadm', '-m',
'discovery',
- self._execute('iscsiadm', '-m',
'discovery',
'-t', 'sendtargets',
'-p', volume['host'],
run_as_root=True)
- mount_device = ("/dev/disk/by-path/ip-
%s-iscsi-%s-lun-0" %
'-p', volume['host'],
run_as_root=True)
- mount_device = ("/dev/disk/by-path/ip-
%s-iscsi-%s-lun-0" %
(iscsi_properties['target_portal'],
iscsi_properties['target_iqn']))
- export 가 안되면
FLAGS.num_iscsi_scan_tries만큼 반복
3-1-5-7-2-3. self.db.volume_attached()
- volumes 테이블의 status, mountpoint, attach_status 값을
in-use, device_name, attached 로 변경
3-1-6. self._instance_update()- export 가 안되면
FLAGS.num_iscsi_scan_tries만큼 반복
3-1-5-7-2-3. self.db.volume_attached()
- volumes 테이블의 status, mountpoint, attach_status 값을
in-use, device_name, attached 로 변경
3-1-6-1. self.db.instance_update()
- instances 테이블에 vm_state 와 task_state 를 BUILDING, SPAWNING 으로 변경
3-1-7. virt/libvirt/connection.py.LibvirtConnection -> spawn()
3-1-7-1. self.to_xml()
3-1-7-1-1. self._prepare_xml_info()
3-1-7-1-1-1. virt/driver.py -> block_device_info_get_mapping()
3-1-7-1-1-2. virt/libvirt/vif.py.LibvirtBridgeDriver -> plug()
- multi_host 가 False 이고 should_create_bridge 가 True
- should_create_vlan 이 True 이면
3-1-7-1-1-2-1. network/linux_net.py.
LinuxBridgeInterfaceDriver
-> ensure_vlan_bridge()
- should_create_vlan 이 False 이면
3-1-7-1-1-2-2. network/linux_net.py.
LinuxBridgeInterfaceDriver
-> ensure_bridge()
3-1-7-1-1-2-3. self._get_configurations()
3-1-7-1-1-3. compute/instance_types.py -> get_instance.type()
3-1-7-1-1-4. self._volume_in_mapping()
3-1-7-1-1-5. virt/driver.py -> block_device_info_get_ephemerals()
3-1-7-1-1-6. virt/driver.py -> block_device_info_get_root()
- root_device_name 이 있다면 그대로 데이터를 이용
- root_device_name 이 없다면
3-1-7-1-1-7. db.instance_update()
- local_device 가 True 라면
3-1-7-1-1-8. db.instance_update()
3-1-7-1-1-9. virt/driver.py -> block_device_info_get_swap()
- FLAGS.vnc_enabled and FLAGS.libvirt_type not in ('lxc', 'uml') 라면
xml_info['vncserver_host'] 및 xml_info['vnc_keymap'] 에 세팅
3-1-7-2. virt/libvirt/firewall.py.IptablesFirewallDriver -> setup_basic_filtering()
3-1-7-2-1. virt/libvirt/firewall.py.NWFilterFirewall -> setup_basic_filtering()
3-1-7-2-1-1. self._ensure_static_filters()
3-1-7-2-1-2. self._define_filter(self._filter_container())
3-1-7-2-2. self.refresh_provider_fw_rules()
3-1-7-2-2-1. self._do_refresh_provider_fw_rules()
3-1-7-2-2-1-1. self._purge_provider_fw_rules()
3-1-7-2-2-1-2. self._build_provider_fw_rules()
3-1-7-2-2-2. self.iptables.apply()
3-1-7-2-2-2-1. network/linux_net.py.IptablesManager
-> apply()
3-1-7-2-2-2-1-1. self._modify_rules()
3-1-7-3. virt/libvirt/firewall.py.IptablesFirewallDriver -> prepare_instance_filter()3-1-7-2-2-2-1. network/linux_net.py.IptablesManager
-> apply()
3-1-7-2-2-2-1-1. self._modify_rules()
3-1-7-3-1. self.add_filters_for_instance()
3-1-7-3-1-1. network/linux_net.py.IpTablesTable -> add_chain()
3-1-7-3-1-2. self._filters_for_instance()
3-1-7-3-1-3. self._add_filters()
3-1-7-3-1-4. self.instance_rules()
3-1-7-3-1-3. self._add_filters()
3-1-7-3-2. network/linux_net.py.IpTablesTable -> apply()
3-1-7-3-2-1. self._modify_rules()
3-1-7-4. self._create_image()
.......
3-1-7-5. self._create_new_domain()
.......
3-1-7-6. virt/libvirt/firewall.py.IptablesFirewallDriver -> apply_instance_filter()
pass
3-1-7-7. utils.py.LoopingCall(_wait_for_boot)
3-1-7-7-1. self.get_info()
- libvirt 로 부터 state를 주기적으로 받아와서 power_state.RUNNING 일 때
멈춤
3-1-7-8. utils.py.LoopingCall -> timer.start()
3-1-8. self._get_power_state()
........
3-1-9. self._instance_update()
3-1-9-1. self.db.instance_update()
- instances 테이블에 power_state, vm_state 와 task_state 를 libvirt를 조회하여
compute/power_state.py.변수, ACTIVE, None 으로 변경
3-1-10. utils.py -> usage_from_instance()
- instance 상태 변수를 넘겨서 usage_info dict 변수 값으로 변경하여 리턴
3-1-11. notifier/api.py -> notify('compute.%s' % self.host,
'compute.instance.create',
notifier.INFO, usage_info)
반응형