{"id":2939,"date":"2024-11-27T17:08:28","date_gmt":"2024-11-27T08:08:28","guid":{"rendered":"https:\/\/manvscloud.com\/?p=2939"},"modified":"2024-11-27T17:08:28","modified_gmt":"2024-11-27T08:08:28","slug":"ncloud-vpc-id%ea%b8%b0%eb%b0%98-%eb%8b%a4%ec%88%98-%ec%84%9c%eb%b2%84-start-stop-scheduling","status":"publish","type":"post","link":"https:\/\/manvscloud.com\/?p=2939","title":{"rendered":"[NCLOUD] VPC ID\uae30\ubc18 \ub2e4\uc218 \uc11c\ubc84 Start\/Stop Scheduling"},"content":{"rendered":"\n<p>\uc548\ub155\ud558\uc138\uc694. ManVSCloud \uae40\uc218\ud604\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\ud074\ub77c\uc6b0\ub4dc \ud658\uacbd\uc5d0\uc11c \ube44\uc6a9 \ucd5c\uc801\ud654\ub294 \ub9e4\uc6b0 \uc911\uc694\ud55c \uc694\uc18c\uc785\ub2c8\ub2e4. <br>\ud2b9\ud788 \uac1c\ubc1c\uc774\ub098 QA \ud658\uacbd\uacfc \uac19\uc774 24\uc2dc\uac04 \uc6b4\uc601\uc774 \ud544\uc694\ud558\uc9c0 \uc54a\uc740 \uc11c\ubc84\ub4e4\uc758 \uacbd\uc6b0 \uc5c5\ubb34 \uc2dc\uac04\uc5d0\ub9cc \uc6b4\uc601\ud558\uace0 \uadf8 \uc678 \uc2dc\uac04\uc5d0\ub294 \uc911\uc9c0\ud558\ub294 \uac83\uc774 \ud6a8\uc728\uc801\uc778 \ube44\uc6a9 \uad00\ub9ac \ubc29\ubc95\uc785\ub2c8\ub2e4.<br>\uc774\uc804\uc5d0 \uc774\ub97c \uc801\uc6a9\ud558\uae30 \uc704\ud574 \ub124\uc774\ubc84 \ud074\ub77c\uc6b0\ub4dc\uc5d0\uc11c \uc11c\ubc84\ub97c \uc2dc\uc791\/\uc911\uc9c0\ud558\ub294 \ubc29\ubc95\uc744 \uacf5\uc720\ud55c \uc801\uc774 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<ul>\n<li><strong>\uc774\uc804 \ud3ec\uc2a4\ud305<\/strong> : [NCLOUD] Cloud Function\uc73c\ub85c \uc6d0\ud558\ub294 \uc2dc\uac04\ub300\uc5d0 \uc11c\ubc84\ub97c \uc2dc\uc791\ud558\uace0 \uc911\uc9c0\ud558\uc790<br> : <a href=\"https:\/\/manvscloud.com\/?p=1803\">https:\/\/manvscloud.com\/?p=1803<\/a><\/li>\n<\/ul>\n\n\n\n<p>\uc774\uc804\uc5d0 \uacf5\uc720\ub4dc\ub9b0 \ubc29\uc2dd\uc740 \uac1c\ubcc4 \uc11c\ubc84\ub97c \uc9c0\uc815\ud558\uc5ec \uc2dc\uc791\/\uc911\uc9c0\ud558\ub294 \ubc29\uc2dd\uc774\uc5c8\uc2b5\ub2c8\ub2e4. <br>\uc774\ub294 \uc18c\uc218\uc758 \uc11c\ubc84\ub9cc \uad00\ub9ac\ud560 \ub54c\ub294 \ud6a8\uacfc\uc801\uc774\uc5c8\uc73c\ub098 \ub2e4\uc218\uc758 \uc11c\ubc84\ub97c \uad00\ub9ac\ud574\uc57c \ud558\ub294 \uacbd\uc6b0\uc5d0\ub294 \uba87 \uac00\uc9c0 \ud55c\uacc4\uc810\uc774 \uc788\uc5c8\uc2b5\ub2c8\ub2e4.<br><br>1) \uc11c\ubc84\uac00 \ub9ce\uc544\uc9c8\uc218\ub85d \uc124\uc815\ud574\uc57c \ud560 \ub300\uc0c1\uc774 \uc99d\uac00\ud558\uc5ec \uad00\ub9ac\uac00 \ubcf5\uc7a1\ud574\uc9d1\ub2c8\ub2e4.<br>2) \uc0c8\ub85c\uc6b4 \uc11c\ubc84\uac00 \ucd94\uac00\ub420 \ub54c\ub9c8\ub2e4 \uc2a4\ucf00\uc904\ub9c1 \uc124\uc815\uc744 \ucd94\uac00\ud574\uc57c \ud569\ub2c8\ub2e4.<br>3) \uac1c\ubc1c\/QA\/\uc6b4\uc601 \ub4f1 \ud658\uacbd\ubcc4\ub85c \uc11c\ubc84\ub97c \uad6c\ubd84\ud558\uc5ec \uad00\ub9ac\ud558\uae30\uac00 \uc5b4\ub835\uc2b5\ub2c8\ub2e4.<br><br>\uc774\ub7ec\ud55c \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574 VPC ID\ub97c \uae30\ubc18\uc73c\ub85c \ud558\ub294 \uc0c8\ub85c\uc6b4 \uc2a4\ucf00\uc904\ub9c1 \ubc29\uc2dd\uc744 \ucd94\uac00\ub85c \uacf5\uc720\ub4dc\ub9ac\uace0\uc790 \ud569\ub2c8\ub2e4.<br>VPC ID \uae30\ubc18 \uc2a4\ucf00\uc904\ub9c1\uc740 \ud2b9\uc815 VPC \ub0b4\uc758 \ubaa8\ub4e0 \uc11c\ubc84\ub97c \ud55c \ubc88\uc5d0 \uc81c\uc5b4\ud560 \uc218 \uc788\uc73c\uba70 \uc608\uc678 \ucc98\ub9ac\uac00 \ud544\uc694\ud55c \uc11c\ubc84\ub294 \ubcc4\ub3c4\ub85c \uc9c0\uc815\ud560 \uc218 \uc788\uc5b4 \ub354\uc6b1 \ud6a8\uc728\uc801\uc778 \uc11c\ubc84 \uad00\ub9ac\uac00 \uac00\ub2a5\ud569\ub2c8\ub2e4.<br>\uc774 \ud3ec\uc2a4\ud305\uc5d0\uc11c\ub294 \ub124\uc774\ubc84 \ud074\ub77c\uc6b0\ub4dc\uc758 Cloud Functions\ub97c \ud65c\uc6a9\ud558\uc5ec VPC ID \uae30\ubc18\uc758 \uc11c\ubc84 \uc2a4\ucf00\uc904\ub9c1 \ubc29\uc2dd\uc744 \uad6c\ud604\ud558\ub294 \ubc29\ubc95\uc744 \uc0c1\uc138\ud788 \uc124\uba85\ud558\ub3c4\ub85d \ud558\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-white-color has-vivid-green-cyan-background-color has-text-color has-background has-link-color wp-elements-86a3b8da0a5c54401c542485aee28cfd\"> VPC ID \uae30\ubc18 \uc11c\ubc84 \uc2a4\ucf00\uc904\ub9c1 \ud504\ub85c\uc138\uc2a4<\/h3>\n\n\n\n<ul>\n<li><strong>VPC ID \uae30\ubc18 \uc2a4\ucf00\uc904\ub9c1 \uad6c\ud604 \uac1c\uc694<\/strong><\/li>\n<\/ul>\n\n\n\n<p>VPC ID \uae30\ubc18 \uc2a4\ucf00\uc904\ub9c1\uc740 Cloud Functions\ub97c \uc0ac\uc6a9\ud558\uc5ec \uad6c\ud604\ub418\uba70, \ud06c\uac8c \uc11c\ubc84 \uc2dc\uc791(Start)\uacfc \uc911\uc9c0(Stop) \ub450 \uac00\uc9c0 \uae30\ub2a5\uc73c\ub85c \uad6c\uc131\ub429\ub2c8\ub2e4. <\/p>\n\n\n\n<p>\uac01 \uae30\ub2a5\uc740 \ub2e4\uc74c\uacfc \uac19\uc740 \ud504\ub85c\uc138\uc2a4\ub85c \ub3d9\uc791\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<ol>\n<li>VPC \ubc88\ud638\ub97c \uae30\ubc18\uc73c\ub85c \ud574\ub2f9 VPC \ub0b4\uc758 \ubaa8\ub4e0 \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \uc870\ud68c<\/li>\n\n\n\n<li>\uc608\uc678 \ucc98\ub9ac\ud560 \uc11c\ubc84 \ubaa9\ub85d \ud655\uc778<\/li>\n\n\n\n<li>\ud604\uc7ac \uc11c\ubc84 \uc0c1\ud0dc \ud655\uc778 \ubc0f \ud544\uc694\ud55c \uc791\uc5c5(\uc2dc\uc791\/\uc911\uc9c0) \uc218\ud589<\/li>\n\n\n\n<li>\uc791\uc5c5 \uacb0\uacfc \ubc18\ud658<\/li>\n<\/ol>\n\n\n\n<ul>\n<li><strong>\uc8fc\uc694 \uae30\ub2a5 \uc0c1\uc138 \uc124\uba85<\/strong><\/li>\n<\/ul>\n\n\n\n<p><strong>1) \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \uc870\ud68c (get_server_instances)<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def get_server_instances(access_key, secret_key, vpc_no):\n    # API \ud638\ucd9c\uc744 \uc704\ud55c \uae30\ubcf8 \uc124\uc815\n    timestamp = str(int(time.time() * 1000))\n    uri = f\"\/vserver\/v2\/getServerInstanceList?responseFormatType=json&amp;regionCode=KR&amp;vpcNo={vpc_no}\"<\/pre>\n\n\n\n<p>\uc774 \ud568\uc218\ub294 \uc9c0\uc815\ub41c VPC \ub0b4\uc758 \ubaa8\ub4e0 \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \uc815\ubcf4\ub97c \uc870\ud68c\ud569\ub2c8\ub2e4. <br>NCLOUD API\ub97c \ud1b5\ud574 \uc11c\ubc84 \ubaa9\ub85d\uc744 \uac00\uc838\uc624\uba70 \uac01 \uc11c\ubc84\uc758 \ud604\uc7ac \uc0c1\ud0dc \uc815\ubcf4\ub3c4 \ud568\uaed8 \uc870\ud68c\ub429\ub2c8\ub2e4.<\/p>\n\n\n\n<p><strong>2) \uc11c\ubc84 \uc2dc\uc791 \uae30\ub2a5<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def start_servers(access_key, secret_key, server_instance_list):\n    if not server_instance_list:\n        return {\"message\": \"No servers to start\"}<\/pre>\n\n\n\n<p>NSTOP \uc0c1\ud0dc\uc778 \uc11c\ubc84\ub4e4\uc744 \ub300\uc0c1\uc73c\ub85c \uc2dc\uc791 \uc791\uc5c5\uc744 \uc218\ud589\ud569\ub2c8\ub2e4. <br>\uc774\ubbf8 \uc2e4\ud589 \uc911\uc778 \uc11c\ubc84\ub294 \uc81c\uc678\ub418\uba70 \uc608\uc678 \ucc98\ub9ac \ubaa9\ub85d\uc5d0 \ud3ec\ud568\ub41c \uc11c\ubc84\ub3c4 \uc2dc\uc791 \ub300\uc0c1\uc5d0\uc11c \uc81c\uc678\ub429\ub2c8\ub2e4.<\/p>\n\n\n\n<p><strong>3) \uc11c\ubc84 \uc911\uc9c0 \uae30\ub2a5<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def stop_servers(access_key, secret_key, server_instance_list):\n    if not server_instance_list:\n        return {\"message\": \"No servers to stop\"}<\/pre>\n\n\n\n<p>RUN \uc0c1\ud0dc\uc778 \uc11c\ubc84\ub4e4\uc744 \ub300\uc0c1\uc73c\ub85c \uc911\uc9c0 \uc791\uc5c5\uc744 \uc218\ud589\ud569\ub2c8\ub2e4. <br>\uc774\ubbf8 \uc911\uc9c0\ub41c \uc11c\ubc84\ub294 \uc81c\uc678\ub418\uba70 \uc608\uc678 \ucc98\ub9ac \ubaa9\ub85d\uc5d0 \ud3ec\ud568\ub41c \uc11c\ubc84\ub294 \uc911\uc9c0 \ub300\uc0c1\uc5d0\uc11c \uc81c\uc678\ub429\ub2c8\ub2e4.<\/p>\n\n\n\n<ul>\n<li><strong>\uc608\uc678 \ucc98\ub9ac \ubc0f \uc548\uc804\uc7a5\uce58<\/strong><\/li>\n<\/ul>\n\n\n\n<p><strong>1) \uc11c\ubc84 \uc0c1\ud0dc \ud655\uc778<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">instance_status = instance.get('serverInstanceStatus', {}).get('code', '')\nif instance_status == \"NSTOP\":  # \uc2dc\uc791 \ud568\uc218\uc758 \uacbd\uc6b0\n    servers_to_start.append(instance_no)\nif instance_status == \"RUN\":    # \uc911\uc9c0 \ud568\uc218\uc758 \uacbd\uc6b0\n    servers_to_stop.append(instance_no)<\/pre>\n\n\n\n<p>\uac01 \uc791\uc5c5 \uc218\ud589 \uc804 \uc11c\ubc84\uc758 \ud604\uc7ac \uc0c1\ud0dc\ub97c \ud655\uc778\ud558\uc5ec \ubd88\ud544\uc694\ud55c API \ud638\ucd9c\uc744 \ubc29\uc9c0\ud558\uace0 \uc548\uc815\uc801\uc778 \uc791\uc5c5 \uc218\ud589\uc744 \ubcf4\uc7a5\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<p><strong>2) \uc608\uc678 \uc11c\ubc84 \uad00\ub9ac<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">excluded_instances = [\"11111111\", \"222222222\", \"33333333\"]  # \uc608\uc2dc ID\nif instance_no in excluded_instances:\n    continue<\/pre>\n\n\n\n<p>\ud2b9\uc815 \uc11c\ubc84\ub97c \uc608\uc678 \ucc98\ub9ac\ud558\uc5ec \uc2a4\ucf00\uc904\ub9c1 \ub300\uc0c1\uc5d0\uc11c \uc81c\uc678\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. <br>\uc774\ub294 24\uc2dc\uac04 \uc6b4\uc601\uc774 \ud544\uc694\ud55c \uc11c\ubc84\ub098 \ud2b9\ubcc4\ud55c \uad00\ub9ac\uac00 \ud544\uc694\ud55c \uc11c\ubc84\ub97c \uc704\ud55c \uae30\ub2a5\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<ul>\n<li><strong>\uc2e4\ud589 \uacb0\uacfc \uad00\ub9ac<\/strong><\/li>\n<\/ul>\n\n\n\n<p>\uac01 \uc791\uc5c5\uc758 \uc2e4\ud589 \uacb0\uacfc\ub294 \uc0c1\uc138\ud55c \uc815\ubcf4\ub97c \ud3ec\ud568\ud558\uc5ec \ubc18\ud658\ub429\ub2c8\ub2e4.<\/p>\n\n\n\n<p>&#8211; \uc81c\uc678\ub41c \uc11c\ubc84 \ubaa9\ub85d<br>&#8211; \uc791\uc5c5 \ub300\uc0c1\uc5d0\uc11c \uc81c\uc678\ub41c \uc11c\ubc84\uc640 \uadf8 \uc0c1\ud0dc<br>&#8211; \uc2e4\uc81c \uc791\uc5c5\uc774 \uc218\ud589\ub41c \uc11c\ubc84 \ubaa9\ub85d<br>&#8211; API \uc751\ub2f5 \uacb0\uacfc<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-white-color has-vivid-green-cyan-background-color has-text-color has-background has-link-color wp-elements-f86ab40d55644db966edc61b9392d7bc\"> \uc804\uccb4 \ucf54\ub4dc \ubc0f Cloud Functions \uc124\uc815<\/h3>\n\n\n\n<ul>\n<li><strong>Cloud Functions &#8211; Action<\/strong><\/li>\n<\/ul>\n\n\n\n<p><strong>\/\/ VPC ID \uae30\ubc18 \uc11c\ubc84 \uc2dc\uc791<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import hashlib\nimport hmac\nimport base64\nimport requests\nimport time\nimport json\n\ndef get_server_instances(access_key, secret_key, vpc_no):\n    timestamp = str(int(time.time() * 1000))\n    secret_key_bytes = bytes(secret_key, 'UTF-8')\n    method = \"GET\"\n    api_server = \"https:\/\/ncloud.apigw.ntruss.com\"\n    uri = f\"\/vserver\/v2\/getServerInstanceList?responseFormatType=json&amp;regionCode=KR&amp;vpcNo={vpc_no}\"\n    \n    message = method + \" \" + uri + \"\\n\" + timestamp + \"\\n\" + access_key\n    message = bytes(message, 'UTF-8')\n    signing_key = base64.b64encode(hmac.new(secret_key_bytes, message, digestmod=hashlib.sha256).digest())\n    \n    http_header = {\n        'x-ncp-apigw-signature-v2': signing_key,\n        'x-ncp-apigw-timestamp': timestamp,\n        'x-ncp-iam-access-key': access_key\n    }\n    \n    response = requests.get(api_server + uri, headers=http_header)\n    return response.json()\n\ndef start_servers(access_key, secret_key, server_instance_list):\n    if not server_instance_list:\n        return {\"message\": \"No servers to start\"}\n        \n    timestamp = str(int(time.time() * 1000))\n    secret_key_bytes = bytes(secret_key, 'UTF-8')\n    method = \"GET\"\n    api_server = \"https:\/\/ncloud.apigw.ntruss.com\"\n    \n    # Create server list query string\n    server_query = \"\"\n    for idx, server_id in enumerate(server_instance_list, 1):\n        server_query += f\"&amp;serverInstanceNoList.{idx}={server_id}\"\n    \n    uri = f\"\/vserver\/v2\/startServerInstances?regionCode=KR{server_query}&amp;responseFormatType=json\"\n    \n    message = method + \" \" + uri + \"\\n\" + timestamp + \"\\n\" + access_key\n    message = bytes(message, 'UTF-8')\n    signing_key = base64.b64encode(hmac.new(secret_key_bytes, message, digestmod=hashlib.sha256).digest())\n    \n    http_header = {\n        'x-ncp-apigw-signature-v2': signing_key,\n        'x-ncp-apigw-timestamp': timestamp,\n        'x-ncp-iam-access-key': access_key\n    }\n    \n    response = requests.get(api_server + uri, headers=http_header)\n    return response.json()\n\ndef main(args):\n    access_key = args[\"NCLOUD_ACCESS_KEY\"]\n    secret_key = args[\"NCLOUD_SECRET_KEY\"]\n    vpc_no = \"1111\"  # VPC \ubc88\ud638\n    excluded_instances = [\"111111\", \"222222\", \"333333\"]  # \uc81c\uc678\ud560 \uc778\uc2a4\ud134\uc2a4 \ubaa9\ub85d\n    \n    # VPC\uc758 \ubaa8\ub4e0 \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \uc870\ud68c\n    instance_response = get_server_instances(access_key, secret_key, vpc_no)\n    \n    # \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \ubaa9\ub85d \ucd94\ucd9c\n    server_instances = instance_response['getServerInstanceListResponse']['serverInstanceList']\n    \n    # \uc81c\uc678\ud560 \uc778\uc2a4\ud134\uc2a4\ub97c \uc81c\uc678\ud558\uace0, NSTOP \uc0c1\ud0dc\uc778 \uc11c\ubc84\ub9cc \ud544\ud130\ub9c1\n    servers_to_start = []\n    skipped_servers = []\n    \n    for instance in server_instances:\n        instance_no = instance['serverInstanceNo']\n        instance_status = instance.get('serverInstanceStatus', {}).get('code', '')\n        \n        if instance_no in excluded_instances:\n            continue\n        \n        # NSTOP \uc0c1\ud0dc\uc758 \uc11c\ubc84\ub9cc \uc2dc\uc791 \ubaa9\ub85d\uc5d0 \ucd94\uac00\n        if instance_status == \"NSTOP\":\n            servers_to_start.append(instance_no)\n        else:\n            skipped_servers.append({\n                \"serverInstanceNo\": instance_no,\n                \"status\": instance_status\n            })\n    \n    # \uc11c\ubc84 \uc2dc\uc791 \uc2e4\ud589\n    result = {\n        \"status\": \"success\",\n        \"result\": {\n            \"excluded\": excluded_instances,\n            \"skipped_servers\": skipped_servers\n        },\n        \"success\": True\n    }\n    \n    if servers_to_start:\n        start_response = start_servers(access_key, secret_key, servers_to_start)\n        result[\"result\"][\"message\"] = f\"Starting {len(servers_to_start)} servers\"\n        result[\"result\"][\"servers_started\"] = servers_to_start\n        result[\"result\"][\"api_response\"] = start_response\n    else:\n        result[\"result\"][\"message\"] = \"No servers to start\"\n    \n    return result<\/pre>\n\n\n\n<p><strong>\/\/ VPC ID \uae30\ubc18 \uc11c\ubc84 \uc911\uc9c0<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import hashlib\nimport hmac\nimport base64\nimport requests\nimport time\nimport json\n\ndef get_server_instances(access_key, secret_key, vpc_no):\n    timestamp = str(int(time.time() * 1000))\n    secret_key_bytes = bytes(secret_key, 'UTF-8')\n    method = \"GET\"\n    api_server = \"https:\/\/ncloud.apigw.ntruss.com\"\n    uri = f\"\/vserver\/v2\/getServerInstanceList?responseFormatType=json&amp;regionCode=KR&amp;vpcNo={vpc_no}\"\n    \n    message = method + \" \" + uri + \"\\n\" + timestamp + \"\\n\" + access_key\n    message = bytes(message, 'UTF-8')\n    signing_key = base64.b64encode(hmac.new(secret_key_bytes, message, digestmod=hashlib.sha256).digest())\n    \n    http_header = {\n        'x-ncp-apigw-signature-v2': signing_key,\n        'x-ncp-apigw-timestamp': timestamp,\n        'x-ncp-iam-access-key': access_key\n    }\n    \n    response = requests.get(api_server + uri, headers=http_header)\n    return response.json()\n\ndef stop_servers(access_key, secret_key, server_instance_list):\n    if not server_instance_list:\n        return {\"message\": \"No servers to stop\"}\n        \n    timestamp = str(int(time.time() * 1000))\n    secret_key_bytes = bytes(secret_key, 'UTF-8')\n    method = \"GET\"\n    api_server = \"https:\/\/ncloud.apigw.ntruss.com\"\n    \n    # Create server list query string\n    server_query = \"\"\n    for idx, server_id in enumerate(server_instance_list, 1):\n        server_query += f\"&amp;serverInstanceNoList.{idx}={server_id}\"\n    \n    uri = f\"\/vserver\/v2\/stopServerInstances?regionCode=KR{server_query}&amp;responseFormatType=json\"\n    \n    message = method + \" \" + uri + \"\\n\" + timestamp + \"\\n\" + access_key\n    message = bytes(message, 'UTF-8')\n    signing_key = base64.b64encode(hmac.new(secret_key_bytes, message, digestmod=hashlib.sha256).digest())\n    \n    http_header = {\n        'x-ncp-apigw-signature-v2': signing_key,\n        'x-ncp-apigw-timestamp': timestamp,\n        'x-ncp-iam-access-key': access_key\n    }\n    \n    response = requests.get(api_server + uri, headers=http_header)\n    return response.json()\n\ndef main(args):\n    access_key = args[\"NCLOUD_ACCESS_KEY\"]\n    secret_key = args[\"NCLOUD_SECRET_KEY\"]\n    vpc_no = \"1111\"  # VPC \ubc88\ud638\n    excluded_instances = [\"1111\", \"2222\"]  # \uc81c\uc678\ud560 \uc778\uc2a4\ud134\uc2a4 \ubaa9\ub85d\n    \n    # VPC\uc758 \ubaa8\ub4e0 \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \uc870\ud68c\n    instance_response = get_server_instances(access_key, secret_key, vpc_no)\n    \n    # \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \ubaa9\ub85d \ucd94\ucd9c\n    server_instances = instance_response['getServerInstanceListResponse']['serverInstanceList']\n    \n    # \uc81c\uc678\ud560 \uc778\uc2a4\ud134\uc2a4\ub97c \uc81c\uc678\ud558\uace0, RUN \uc0c1\ud0dc\uc778 \uc11c\ubc84\ub9cc \ud544\ud130\ub9c1\n    servers_to_stop = []\n    skipped_servers = []\n    \n    for instance in server_instances:\n        instance_no = instance['serverInstanceNo']\n        instance_status = instance.get('serverInstanceStatus', {}).get('code', '')\n        \n        if instance_no in excluded_instances:\n            continue\n            \n        # RUN \uc0c1\ud0dc\uc758 \uc11c\ubc84\ub9cc \uc911\uc9c0 \ubaa9\ub85d\uc5d0 \ucd94\uac00\n        if instance_status == \"RUN\":\n            servers_to_stop.append(instance_no)\n        else:\n            skipped_servers.append({\n                \"serverInstanceNo\": instance_no,\n                \"status\": instance_status\n            })\n    \n    # \uacb0\uacfc \uc751\ub2f5 \uc900\ube44\n    result = {\n        \"status\": \"success\",\n        \"result\": {\n            \"excluded\": excluded_instances,\n            \"skipped_servers\": skipped_servers\n        },\n        \"success\": True\n    }\n    \n    # \uc11c\ubc84 \uc911\uc9c0 \uc2e4\ud589\n    if servers_to_stop:\n        stop_response = stop_servers(access_key, secret_key, servers_to_stop)\n        result[\"result\"][\"message\"] = f\"Stopping {len(servers_to_stop)} servers\"\n        result[\"result\"][\"servers_stopped\"] = servers_to_stop\n        result[\"result\"][\"api_response\"] = stop_response\n    else:\n        result[\"result\"][\"message\"] = \"No servers to stop\"\n    \n    return result<\/pre>\n\n\n\n<p><strong>\/\/<\/strong> <strong>VPC ID \uae30\ubc18 \uc11c\ubc84 \uc2dc\uc791\/\uc911\uc9c0 \uacf5\ud1b5 \ub514\ud3f4\ud2b8 \ud30c\ub77c\ubbf8\ud130<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\"NCLOUD_ACCESS_KEY\": \"VPC\uc870\ud68c \ubc0f \uc11c\ubc84 \uc2dc\uc791,\uc911\uc9c0 \uad8c\ud55c\uc774 \uc788\ub294 Access Key\", \"NCLOUD_SECRET_KEY\": \"VPC\uc870\ud68c \ubc0f \uc11c\ubc84 \uc2dc\uc791,\uc911\uc9c0 \uad8c\ud55c\uc774 \uc788\ub294 Access Key\uc758 Secret Key\"}<\/pre>\n\n\n\n<p>Cloud Functions Action \uc0dd\uc131 \uc2dc \ub514\ud3f4\ud2b8 \ud30c\ub77c\ubbf8\ud130\uc5d0 NCLOUD_ACCESS_KEY\uc640 NCLOUD_SECRET_KEY\ub97c \ucd94\uac00\ud574\uc90d\ub2c8\ub2e4. \ub2f9\uc5f0\ud788 \ud574\ub2f9 \uc561\uc138\uc2a4 \ud0a4\ub294 \ucf58\uc194 \uc811\uc18d\uc774 \ubd88\uac00\ub2a5\ud55c Programmatic User\ub85c \uc0dd\uc131\ub418\uc5b4\uc57c \ud558\uba70 \uc704 \ucf54\ub4dc\ub97c \uc815\uc0c1\uc801\uc73c\ub85c \uc2e4\ud589\ud560 \uc218 \uc788\ub3c4\ub85d VPC \uc870\ud68c \ubc0f \uc11c\ubc84 \uc2dc\uc791, \uc911\uc9c0 \uad8c\ud55c\uc774 \uc815\ucc45\uc73c\ub85c \ud3ec\ud568\ub418\uc5b4\uc57c \ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<ul>\n<li><strong>Cloud Functions &#8211; Trigger<\/strong><br>: cron<\/li>\n<\/ul>\n\n\n\n<p>\uc6d0\ud558\ub294 \uc2dc\uac04\ub300\uc5d0 \uc911\uc9c0, \uc6d0\ud558\ub294 \uc2dc\uac04\ub300\uc5d0 \uc2dc\uc791\ud574\uc57c\ud558\ubbc0\ub85c Trigger\ub294 Cron\uc774 \ucd5c\uc801\uc758 \ubc29\uc2dd\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-white-color has-cyan-bluish-gray-background-color has-text-color has-background has-link-color wp-elements-790b4ede7486cf11fc8601a67c8dcb47\"> Personal Comments<\/h3>\n\n\n\n<p>VPC ID \uae30\ubc18\uc758 \uc11c\ubc84 \uc2a4\ucf00\uc904\ub9c1 \ubc29\uc2dd\uc740 \uae30\uc874 \uac1c\ubcc4 \uc11c\ubc84 \uc9c0\uc815 \ubc29\uc2dd\uc758 \ud55c\uacc4\ub97c \uadf9\ubcf5\ud558\uace0 \ub2e4\uc74c\uacfc \uac19\uc740 \uc774\uc810\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<ul>\n<li>VPC \ub2e8\uc704\uc758 \ud1b5\ud569 \uad00\ub9ac\ub85c \ub2e4\uc218 \uc11c\ubc84\uc758 \ud6a8\uc728\uc801 \uc81c\uc5b4\uac00 \uac00\ub2a5\ud569\ub2c8\ub2e4.<\/li>\n\n\n\n<li>\uc608\uc678 \uc11c\ubc84 \uc9c0\uc815\uc744 \ud1b5\ud574 \uc720\uc5f0\ud55c \uc6b4\uc601\uc774 \uac00\ub2a5\ud569\ub2c8\ub2e4.<\/li>\n\n\n\n<li>\uc11c\ubc84 \uc0c1\ud0dc \ud655\uc778 \ubc0f \uc0c1\uc138\ud55c \uacb0\uacfc \uc81c\uacf5\uc73c\ub85c \uc548\uc815\uc801\uc778 \uc6b4\uc601\uc744 \ubcf4\uc7a5\ud569\ub2c8\ub2e4.<\/li>\n\n\n\n<li>\ubd88\ud544\uc694\ud55c \uc11c\ubc84 \uc6b4\uc601 \uc2dc\uac04\uc744 \uc904\uc5ec \ube44\uc6a9\uc744 \ucd5c\uc801\ud654\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/li>\n<\/ul>\n\n\n\n<p>\uc774\ub7ec\ud55c \ubc29\uc2dd\uc740 \ud2b9\ud788 \uac1c\ubc1c\/QA \ud658\uacbd\uc5d0\uc11c \uc2dc\uac04\ub300\ubcc4\ub85c \uc11c\ubc84 \uad00\ub9ac\ub97c \uc6d0\ud558\ub294 \uacbd\uc6b0 \uc6b4\uc601 \ud6a8\uc728\uc131\uc744 \ud06c\uac8c \ud5a5\uc0c1\uc2dc\ud0ac \uc218 \uc788\uae30\ub54c\ubb38\uc5d0 \ub9ce\uc774 \uacf5\uc720 \ubc0f \ud65c\uc6a9\ub418\uae38 \ubc14\ub78d\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\uae34 \uae00 \uc77d\uc5b4\uc8fc\uc154\uc11c \uac10\uc0ac\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"137\" src=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master.png\" alt=\"\" class=\"wp-image-1221\" srcset=\"https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master.png 800w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master-300x51.png 300w, https:\/\/cdn.manvscloud.com\/wp-content\/uploads\/2021\/08\/10202040\/ncloud-master-768x132.png 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\uc548\ub155\ud558\uc138\uc694. ManVSCloud \uae40\uc218\ud604\uc785\ub2c8\ub2e4. \ud074\ub77c\uc6b0\ub4dc \ud658\uacbd\uc5d0\uc11c \ube44\uc6a9 \ucd5c\uc801\ud654\ub294 \ub9e4\uc6b0 \uc911\uc694\ud55c \uc694\uc18c\uc785\ub2c8\ub2e4. \ud2b9\ud788 \uac1c\ubc1c\uc774\ub098 QA \ud658\uacbd\uacfc \uac19\uc774 24\uc2dc\uac04 \uc6b4\uc601\uc774 \ud544\uc694\ud558\uc9c0 \uc54a\uc740 \uc11c\ubc84\ub4e4\uc758 \uacbd\uc6b0 \uc5c5\ubb34 \uc2dc\uac04\uc5d0\ub9cc \uc6b4\uc601\ud558\uace0 \uadf8 \uc678 \uc2dc\uac04\uc5d0\ub294 \uc911\uc9c0\ud558\ub294 \uac83\uc774 \ud6a8\uc728\uc801\uc778 \ube44\uc6a9 \uad00\ub9ac \ubc29\ubc95\uc785\ub2c8\ub2e4.\uc774\uc804\uc5d0 \uc774\ub97c \uc801\uc6a9\ud558\uae30 \uc704\ud574 \ub124\uc774\ubc84 \ud074\ub77c\uc6b0\ub4dc\uc5d0\uc11c \uc11c\ubc84\ub97c \uc2dc\uc791\/\uc911\uc9c0\ud558\ub294 \ubc29\ubc95\uc744 \uacf5\uc720\ud55c \uc801\uc774 \uc788\uc2b5\ub2c8\ub2e4. \uc774\uc804\uc5d0 \uacf5\uc720\ub4dc\ub9b0 \ubc29\uc2dd\uc740 \uac1c\ubcc4 \uc11c\ubc84\ub97c \uc9c0\uc815\ud558\uc5ec \uc2dc\uc791\/\uc911\uc9c0\ud558\ub294 \ubc29\uc2dd\uc774\uc5c8\uc2b5\ub2c8\ub2e4. \uc774\ub294 \uc18c\uc218\uc758 \uc11c\ubc84\ub9cc \uad00\ub9ac\ud560 \ub54c\ub294 \ud6a8\uacfc\uc801\uc774\uc5c8\uc73c\ub098 \ub2e4\uc218\uc758 \uc11c\ubc84\ub97c \uad00\ub9ac\ud574\uc57c \ud558\ub294 \uacbd\uc6b0\uc5d0\ub294 \uba87 \uac00\uc9c0 \ud55c\uacc4\uc810\uc774 \uc788\uc5c8\uc2b5\ub2c8\ub2e4. 1) \uc11c\ubc84\uac00 \ub9ce\uc544\uc9c8\uc218\ub85d \uc124\uc815\ud574\uc57c \ud560 \ub300\uc0c1\uc774 \uc99d\uac00\ud558\uc5ec \uad00\ub9ac\uac00 \ubcf5\uc7a1\ud574\uc9d1\ub2c8\ub2e4.2) \uc0c8\ub85c\uc6b4 \uc11c\ubc84\uac00 \ucd94\uac00\ub420 \ub54c\ub9c8\ub2e4 \uc2a4\ucf00\uc904\ub9c1 \uc124\uc815\uc744 \ucd94\uac00\ud574\uc57c \ud569\ub2c8\ub2e4.3) \uac1c\ubc1c\/QA\/\uc6b4\uc601 \ub4f1 \ud658\uacbd\ubcc4\ub85c \uc11c\ubc84\ub97c \uad6c\ubd84\ud558\uc5ec \uad00\ub9ac\ud558\uae30\uac00 \uc5b4\ub835\uc2b5\ub2c8\ub2e4. \uc774\ub7ec\ud55c \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574 VPC ID\ub97c \uae30\ubc18\uc73c\ub85c \ud558\ub294 \uc0c8\ub85c\uc6b4 \uc2a4\ucf00\uc904\ub9c1 \ubc29\uc2dd\uc744 \ucd94\uac00\ub85c \uacf5\uc720\ub4dc\ub9ac\uace0\uc790 \ud569\ub2c8\ub2e4.VPC ID \uae30\ubc18 \uc2a4\ucf00\uc904\ub9c1\uc740 \ud2b9\uc815 VPC \ub0b4\uc758 \ubaa8\ub4e0 \uc11c\ubc84\ub97c \ud55c \ubc88\uc5d0 \uc81c\uc5b4\ud560 \uc218 \uc788\uc73c\uba70 \uc608\uc678 \ucc98\ub9ac\uac00 \ud544\uc694\ud55c \uc11c\ubc84\ub294 \ubcc4\ub3c4\ub85c \uc9c0\uc815\ud560 \uc218 \uc788\uc5b4 \ub354\uc6b1 \ud6a8\uc728\uc801\uc778 \uc11c\ubc84 \uad00\ub9ac\uac00 \uac00\ub2a5\ud569\ub2c8\ub2e4.\uc774 \ud3ec\uc2a4\ud305\uc5d0\uc11c\ub294 \ub124\uc774\ubc84 \ud074\ub77c\uc6b0\ub4dc\uc758 Cloud Functions\ub97c \ud65c\uc6a9\ud558\uc5ec VPC ID \uae30\ubc18\uc758 \uc11c\ubc84 \uc2a4\ucf00\uc904\ub9c1 \ubc29\uc2dd\uc744 \uad6c\ud604\ud558\ub294 \ubc29\ubc95\uc744 \uc0c1\uc138\ud788 \uc124\uba85\ud558\ub3c4\ub85d \ud558\uaca0\uc2b5\ub2c8\ub2e4. VPC ID \uae30\ubc18 \uc11c\ubc84 \uc2a4\ucf00\uc904\ub9c1 \ud504\ub85c\uc138\uc2a4 VPC ID \uae30\ubc18 \uc2a4\ucf00\uc904\ub9c1\uc740 Cloud Functions\ub97c \uc0ac\uc6a9\ud558\uc5ec \uad6c\ud604\ub418\uba70, \ud06c\uac8c \uc11c\ubc84 \uc2dc\uc791(Start)\uacfc \uc911\uc9c0(Stop) \ub450 \uac00\uc9c0 \uae30\ub2a5\uc73c\ub85c \uad6c\uc131\ub429\ub2c8\ub2e4. \uac01 \uae30\ub2a5\uc740 \ub2e4\uc74c\uacfc \uac19\uc740 \ud504\ub85c\uc138\uc2a4\ub85c \ub3d9\uc791\ud569\ub2c8\ub2e4. 1) \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \uc870\ud68c (get_server_instances) \uc774 \ud568\uc218\ub294 \uc9c0\uc815\ub41c VPC \ub0b4\uc758 \ubaa8\ub4e0 \uc11c\ubc84 \uc778\uc2a4\ud134\uc2a4 \uc815\ubcf4\ub97c \uc870\ud68c\ud569\ub2c8\ub2e4. NCLOUD API\ub97c \ud1b5\ud574 \uc11c\ubc84 \ubaa9\ub85d\uc744 \uac00\uc838\uc624\uba70 \uac01 \uc11c\ubc84\uc758 \ud604\uc7ac [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[457,32,87,91,17,90,16,805,89,202,398,681,683,993,584],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts\/2939"}],"collection":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2939"}],"version-history":[{"count":7,"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts\/2939\/revisions"}],"predecessor-version":[{"id":2946,"href":"https:\/\/manvscloud.com\/index.php?rest_route=\/wp\/v2\/posts\/2939\/revisions\/2946"}],"wp:attachment":[{"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2939"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2939"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/manvscloud.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2939"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}