def add(): """ 录入新的应用 :return: """ ps = request.values name = ps.get('name') version = ps.get('version', default="1.0.0") notEmptyStr(name=name, version=version) id = ps.get('id') app = Application(name=name, id=id, version=version, remark=ps.get('remark')) if id and int(id) > 0: oldApp = Application.query.get(id) if oldApp is None: raise ServiceException("ID=%d 的应用不存在故不能编辑" % id) copyEntityBean(app, oldApp) else: # 判断应用名是否重复 oldApp = Application.query.getOne(name=name) if oldApp: raise ServiceException("应用 %s 已经存在,不能重复录入" % name) db.session.add(app) db.session.commit() op = "录入" if id is 0 else "编辑" LOG.info("%s应用 %s" % (op, app)) return jsonify(Result.ok("应用 %s %s成功(版本=%s)" % (name, op, version), app.id))
def filesystemContent(name): """ :param name: :return: """ location = Q("location", "", str) file = os.path.join(__detect_app_dir(name), location) if not os.path.exists(file): raise ServiceException("查询的文件不存在:%s" % location) # 读取前 1024 字节判断文本类型 raw = open(file, 'rb').read(min(512, os.path.getsize(file))) result = chardet.detect(raw) encoding = result['encoding'] with open(file, 'r', encoding=encoding) as f: try: return jsonify(Result.ok(data=f.read())) except Exception as e: raise ServiceException("尝试用编码 {} 读取 {} 但不成功:{}".format( encoding, location, str(e)))
def install(): """ 安装 docker ,只支持 linux 系统 对于 Linux 系统,直接执行 curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh - 快速安装 docker, 详见:https://yq.aliyun.com/articles/7695?spm=5176.100239.blogcont29941.14.kJOgzy :return: """ is_linux = sys.platform == 'Linux' if not is_linux: raise ServiceException("只支持在 Linux 系统下安装 docker(其他平台请手动安装)") # cmd = "curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -" pass
def filesystemUpload(name): """ 上传新文件 :param name: :return: """ file = __detect_file() location = Q("location", "", str) target_file = os.path.join(__detect_app_dir(name), location, file.filename) # 如果文件已经存在,则取消上传 if os.path.exists(target_file): raise ServiceException("目标文件已经存在:%s/%s" % (location, file.filename)) file.save(target_file) return jsonify(Result.ok("文件成功上传到 %s/%s" % (location, file.filename)))
def __loadApp(aid): app = Application.query.get(aid) if app: return app else: raise ServiceException("ID={} 的应用不存在".format(aid))
def __detect_file(form_name="file"): file = request.files[form_name] if file is None: raise ServiceException("无法检测到文件,请先上传") return file
def load_from_file(file_path: str, application: Application, update=False, **kwargs): """ 从指定的目录加载文件(用户上传的文件要求为`zip`格式的压缩文件) :param application: :param update: True = 迭代更新,False = 全新部署 :param file_path: :param kwargs: remove 是否移除同名的旧容器,默认 True :return: """ if file_path is None or not os.path.exists(file_path): raise ServiceException("参数 file_path 未定义或者找不到相应的文件:%s" % file_path) if not file_path.endswith(ZIP): raise ServiceException("load_from_file 只支持 %s 结尾的文件" % ZIP) app_dir = detect_app_dir(application) if update: files = update_app_with_zip(file_path, app_dir) return application.name, files unzip_dir, files = unzip(file_path) LOG.info("解压到 %s" % unzip_dir) container_name = application.name for file in [str(f) for f in files]: LOG.debug("processing %s", file) if file.endswith(TAR): LOG.info("检测到 %s 文件 %s,即将导入该镜像..." % (TAR, file)) docker.loadImage(os.path.join(unzip_dir, file)) LOG.info("docker 镜像导入成功") if file.endswith(ZIP): """对于 zip 格式的文件,解压到程序根目录""" unzip(os.path.join(unzip_dir, file), app_dir) LOG.info("解压 %s 到 %s" % (file, app_dir)) if file in ["{}-{}.jar".format(application.name, application.version), "{}.jar".format(application.name)]: """ 对于 {application.name}.jar 、 {application.name}-{version}.jar 的文件,直接复制到 app_dir 通常经过 spring-boot 打包的 jar 可以直接运行 """ copyFileToDir(os.path.join(unzip_dir, file), app_dir) if file == APP_JSON: with open(os.path.join(unzip_dir, file)) as app_json: content = __transform_placeholder(app_json.read(), application) LOG.info("获取并填充 %s :%s" % (APP_JSON, content)) app_ps = json.loads(content) if 'args' not in app_ps: app_ps['args'] = {} if 'image' not in app_ps: raise ServiceException("{} 中必须定义 'image' 属性,否则无法创建容器".format(APP_JSON)) container_name = detect_app_name(app_ps['args'], app_ps['image']) LOG.info("检测到 容器名:%s", container_name) # 判断是否需要移除旧的 container old_container = None if kwargs.pop("remove", True): try: old_container = docker.getContainer(container_name) LOG.info("name={} 的容器已经存在:{}, id={}".format(container_name, old_container, old_container.id)) except Exception: pass if old_container is not None: try: old_container.remove() LOG.info("成功删除name=%s 的容器" % container_name) except Exception as e: raise ServiceException("无法删除 name={} 的容器: {}".format(container_name, str(e))) network = docker.createDefaultNetwork() app_ps['args']['network'] = network.name docker.createContainer(app_ps['image'], container_name, app_ps['cmd'], app_ps['args']) LOG.info("APP 容器 创建成功(image=%s,name=%s, network=%s)" % (app_ps['image'], container_name, network.name)) shutil.rmtree(unzip_dir) return container_name, files