├── 7mu_oracle_arm.py ├── README.md └── requirements.txt /7mu_oracle_arm.py: -------------------------------------------------------------------------------- 1 | import oci 2 | import re 3 | import time 4 | from oci.core import ComputeClient, VirtualNetworkClient 5 | from oci.config import validate_config 6 | import sys 7 | import requests 8 | import random 9 | import base64 10 | # tg pusher config 11 | USE_TG = False # 如果启用tg推送 要设置为True 12 | TG_BOT_TOKEN = '' # 通过 @BotFather 申请获得,示例:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw 13 | TG_USER_ID = '' # 用户、群组或频道 ID,示例:129xxx206 14 | TG_API_HOST = 'api.telegram.org' # 自建 API 反代地址,供网络环境无法访问时使用,网络正常则保持默认 15 | 16 | 17 | def telegram(desp): 18 | data = (('chat_id', TG_USER_ID), ('text', '🐢 甲骨文ARM抢注脚本为您播报 🐢 \n\n' + desp)) 19 | response = requests.post('https://' + TG_API_HOST + '/bot' + TG_BOT_TOKEN + 20 | '/sendMessage', 21 | data=data) 22 | if response.status_code != 200: 23 | print('Telegram Bot 推送失败') 24 | else: 25 | print('Telegram Bot 推送成功') 26 | 27 | 28 | class OciUser: 29 | """ 30 | oci 用户配置文件的类 31 | """ 32 | user: str 33 | fingerprint: str 34 | key_file: str 35 | tenancy: str 36 | region: str 37 | 38 | def __init__(self, configfile="~/.oci/config", profile="DEFAULT"): 39 | # todo 用户可以自定义制定config文件地址,暂时懒得写 40 | cfg = oci.config.from_file(file_location=configfile, 41 | profile_name=profile) 42 | validate_config(cfg) 43 | self.parse(cfg) 44 | 45 | def parse(self, cfg) -> None: 46 | print("parser cfg") 47 | self.user = cfg['user'] 48 | self.fingerprint = cfg["fingerprint"] 49 | self.key_file = cfg["key_file"] 50 | self.tenancy = cfg['tenancy'] 51 | self.region = cfg['region'] 52 | 53 | def keys(self): 54 | return ("user", "fingerprint", "key_file", "tenancy", "region") 55 | 56 | def __getitem__(self, item): 57 | return getattr(self, item) 58 | 59 | def compartment_id(self): 60 | return self.tenancy 61 | 62 | 63 | class FileParser: 64 | def __init__(self, file_path: str) -> None: 65 | self.parser(file_path) 66 | 67 | def parser(self, file_path): 68 | # compoartment id 69 | # print("开始解析参数") 70 | 71 | try: 72 | print("filepath", file_path) 73 | f = open(file_path, "r") 74 | self._filebuf = f.read() 75 | f.close() 76 | 77 | except Exception as e: 78 | print("main.tf文件打开失败,请再一次确认执行了正确操作,脚本退出", e) 79 | exit(0) 80 | 81 | compoartment_pat = re.compile('compartment_id = "(.*)"') 82 | self.compoartment_id = compoartment_pat.findall(self._filebuf).pop() 83 | 84 | # 内存 85 | memory_pat = re.compile('memory_in_gbs = "(.*)"') 86 | self.memory_in_gbs = float(memory_pat.findall(self._filebuf).pop()) 87 | # 查找cpu个数 88 | cpu_pat = re.compile('ocpus = "(.*)"') 89 | self.ocpus = float(cpu_pat.findall(self._filebuf).pop()) 90 | 91 | # 可用域 92 | ava_domain_pat = re.compile('availability_domain = "(.*)"') 93 | 94 | self.availability_domain = ava_domain_pat.findall(self._filebuf).pop() 95 | 96 | # 子网id 97 | subnet_pat = re.compile('subnet_id = "(.*)"') 98 | self.subnet_id = subnet_pat.findall(self._filebuf).pop() 99 | # 实例名称 100 | disname_pat = re.compile('display_name = "(.*)"') 101 | disname = disname_pat.findall(self._filebuf).pop() 102 | self.display_name = disname.strip().replace(" ", "-") 103 | 104 | # imageid 105 | imageid_pat = re.compile('source_id = "(.*)"') 106 | self.image_id = imageid_pat.findall(self._filebuf)[0] 107 | # 硬盘大小 108 | oot_volume_size_in_gbs_pat = re.compile( 109 | 'boot_volume_size_in_gbs = "(.*)"') 110 | try: 111 | self.boot_volume_size_in_gbs = float( 112 | oot_volume_size_in_gbs_pat.findall(self._filebuf).pop()) 113 | except IndexError: 114 | self.boot_volume_size_in_gbs = 50.0 115 | 116 | # print("硬盘大小", self.boot_volume_size_in_gbs) 117 | # 读取密钥 118 | ssh_rsa_pat = re.compile('"ssh_authorized_keys" = "(.*)"') 119 | try: 120 | self.ssh_authorized_keys = ssh_rsa_pat.findall(self._filebuf).pop() 121 | except Exception as e: 122 | print("推荐创建堆栈的时候下载ssh key,理论上是可以不用的,但是我没写😂,麻烦重新创建吧") 123 | 124 | @property 125 | def ssh_authorized_keys(self): 126 | self._sshkey 127 | 128 | @ssh_authorized_keys.setter 129 | def ssh_authorized_keys(self, key): 130 | self._sshkey = key 131 | 132 | @property 133 | def boot_volume_size_in_gbs(self): 134 | return self._volsize 135 | 136 | @boot_volume_size_in_gbs.setter 137 | def boot_volume_size_in_gbs(self, size): 138 | self._volsize = size 139 | 140 | @property 141 | def image_id(self): 142 | return self._imgid 143 | 144 | @image_id.setter 145 | def image_id(self, imageid): 146 | self._imgid = imageid 147 | 148 | @property 149 | def display_name(self): 150 | return self._dname 151 | 152 | @display_name.setter 153 | def display_name(self, name): 154 | self._dname = name 155 | 156 | @property 157 | def subnet_id(self): 158 | return self._subid 159 | 160 | @subnet_id.setter 161 | def subnet_id(self, sid): 162 | self._subid = sid 163 | 164 | @property 165 | def compoartment_id(self): 166 | return self._comid 167 | 168 | @compoartment_id.setter 169 | def compoartment_id(self, cid): 170 | self._comid = cid 171 | 172 | @property 173 | def memory_in_gbs(self): 174 | return self._mm 175 | 176 | @memory_in_gbs.setter 177 | def memory_in_gbs(self, mm): 178 | self._mm = mm 179 | 180 | @property 181 | def ocpus(self): 182 | return self._cpu 183 | 184 | @ocpus.setter 185 | def ocpus(self, cpu_count): 186 | self._cpu = cpu_count 187 | 188 | @property 189 | def availability_domain(self): 190 | return self._adomain 191 | 192 | @availability_domain.setter 193 | def availability_domain(self, domain): 194 | self._adomain = domain 195 | 196 | 197 | class InsCreate: 198 | shape = 'VM.Standard.A1.Flex' 199 | sleep_time = 10.0 200 | try_count = 0 201 | desp = "" 202 | 203 | def __init__(self, user: OciUser, filepath) -> None: 204 | self._user = user 205 | self._client = ComputeClient(config=dict(user)) 206 | self.tf = FileParser(filepath) 207 | 208 | def gen_pwd(self): 209 | passwd = ''.join( 210 | random.sample( 211 | 'ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba#@1234567890', 212 | 13)) 213 | print("创建ssh登陆密码:{}\n".format(passwd)) 214 | self._pwd = passwd 215 | sh = '#!/bin/bash \n echo root:' + passwd + " | sudo chpasswd root\n sudo sed -i 's/^.*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config;\n sudo sed -i 's/^.*PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config;\n sudo reboot" 216 | sh64 = base64.b64encode(sh.encode('utf-8')) 217 | sh64 = str(sh64, 'utf-8') 218 | self._slcmd = sh64 219 | 220 | def create(self): 221 | # print("与运行创建活动") 222 | # 开启一个tg的原始推送 223 | text = "脚本已启动:\n正在极速抢注以下配置小🐔\n\n区域: {}\n实例: {}\nCPU: {}C\n内存: {}G\n硬盘: {}G\n\n博客: https://blog.iyume.top".format( 224 | self.tf.availability_domain, self.tf.display_name, self.tf.ocpus, 225 | self.tf.memory_in_gbs, self.tf.boot_volume_size_in_gbs) 226 | telegram(text) 227 | self.gen_pwd() 228 | while True: 229 | try: 230 | ins = self.lunch_instance() # 应该返回具体的成功的数据 231 | except oci.exceptions.ServiceError as e: 232 | if e.status == 429 and e.code == 'TooManyRequests' and e.message == 'Too many requests for the user': 233 | # 被限速了,改一下时间 234 | print("请求太快了,正在自动调整请求时间") 235 | if self.sleep_time < 60: 236 | self.sleep_time += 10 237 | elif not (e.status == 500 and e.code == 'InternalError' 238 | and e.message == 'Out of host capacity.'): 239 | if "Service limit" in e.message and e.status==400: 240 | 241 | # 可能是别的错误,也有可能是 达到上限了,要去查看一下是否开通成功,也有可能错误了 242 | self.logp("❌ 如果看到这条推送,说明刷到机器,但是开通失败了,请后台检查你的cpu,内存,硬盘占用情况,并释放对应的资源 返回值:{},\n 脚本停止".format(e)) 243 | else: 244 | self.logp("❌ 发生错误,脚本停止!相关问题:{}".format(e)) 245 | telegram(self.desp) 246 | raise e 247 | else: 248 | # 没有被限速,恢复减少的时间 249 | print("目前没有请求限速,快马加刷中") 250 | if self.sleep_time > 20: 251 | self.sleep_time -= 10 252 | print("本次返回信息:",e) 253 | time.sleep(self.sleep_time) 254 | else: 255 | self.logp( 256 | "🎉 经过 {} 尝试后\n区域编号: {}\n实例名称: {}\nCPU核数: {}C\n内存大小: {}G\n硬盘容量: {}G\n🐔 已创建成功 🎉\n".format( 257 | self.try_count + 1, 258 | self.tf.availability_domain, 259 | self.tf.display_name, 260 | self.tf.ocpus, 261 | self.tf.memory_in_gbs, 262 | self.tf.boot_volume_size_in_gbs 263 | )) 264 | self.ins_id = ins.id 265 | self.logp("SSH密码: {} \n".format(self._pwd)) 266 | self.check_public_ip() 267 | 268 | telegram(self.desp) 269 | break 270 | finally: 271 | self.try_count += 1 272 | print("抢注中,已经经过:{}尝试".format(self.try_count)) 273 | 274 | def check_public_ip(self): 275 | 276 | network_client = VirtualNetworkClient(config=dict(self._user)) 277 | count=100 278 | while count: 279 | attachments = self._client.list_vnic_attachments( 280 | compartment_id=self._user.compartment_id(), 281 | instance_id=self.ins_id) 282 | data = attachments.data 283 | if len(data) != 0: 284 | print("开始查找vnic id ") 285 | vnic_id = data[0].vnic_id 286 | public_ip = network_client.get_vnic(vnic_id).data.public_ip 287 | self.logp("公网ip为:{}\n🐢 脚本停止,感谢使用 😄 \n".format(public_ip)) 288 | self.public_ip = public_ip 289 | self.logp("博客: https://blog.iyume.top") 290 | return 291 | time.sleep(5) 292 | count-=1 293 | self.logp("开机失败,机器被甲骨文给关掉了😠,脚本停止,请重新运行\n") 294 | 295 | def lunch_instance(self): 296 | return self._client.launch_instance( 297 | oci.core.models.LaunchInstanceDetails( 298 | display_name=self.tf.display_name, 299 | compartment_id=self.tf.compoartment_id, 300 | shape=self.shape, 301 | extended_metadata={'user_data': self._slcmd}, 302 | shape_config=oci.core.models.LaunchInstanceShapeConfigDetails( 303 | ocpus=self.tf.ocpus, memory_in_gbs=self.tf.memory_in_gbs), 304 | availability_domain=self.tf.availability_domain, 305 | create_vnic_details=oci.core.models.CreateVnicDetails( 306 | subnet_id=self.tf.subnet_id, 307 | hostname_label=self.tf.display_name), 308 | source_details=oci.core.models.InstanceSourceViaImageDetails( 309 | image_id=self.tf.image_id, 310 | boot_volume_size_in_gbs=self.tf.boot_volume_size_in_gbs, 311 | ), 312 | metadata=dict(ssh_authorized_keys=self.tf.ssh_authorized_keys), 313 | is_pv_encryption_in_transit_enabled=True, 314 | )).data 315 | 316 | def logp(self, text): 317 | print(text) 318 | if USE_TG: 319 | self.desp += text 320 | 321 | 322 | if __name__ == "__main__": 323 | user = OciUser() 324 | path = sys.argv[1] 325 | ins = InsCreate(user, path) 326 | ins.create() 327 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Star History 点亮项目星星! 2 | 3 | [![Star History Chart](https://api.star-history.com/svg?repos=cimmu/oracle-arm&type=Date)](https://star-history.com/#cimmu/oracle-arm&Date) 4 | 5 | # oracle-arm 6 | Oracle cloud arm server auto-snap script 甲骨文乌龟壳自动抢ARM脚本 7 | ![visitors](https://visitor-badge.glitch.me/badge?page_id=cimmu.oracle-arm) 8 | 9 | # 本脚本优点 10 | 11 | 简单,主机配置好 oci config,然后下载 main.tf 即可,不用自己解析各种参数,自动设置ssh登陆密码。 12 | 13 | oci 请求几乎无延迟(为了保险起见加了10s的间隔,会自动判断请求返回值动态调整请求时间). 14 | 15 | 自动获取开机的**公网IP**,无需登陆后台即可ssh上🐔。 16 | 17 | [点击查看完整使用教程](https://blog.iyume.top/other/136.html) 18 | 19 | 2022年5月6号首尔ARM开机成功 20 | 21 | ![image](https://user-images.githubusercontent.com/92285183/167255224-bbc640ac-f928-4a05-9688-143398062b8c.png) 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | oci==2.49.1 2 | requests==2.26.0 3 | --------------------------------------------------------------------------------