├── LICENSE ├── README.md ├── .gitignore └── merge.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 guoxudong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 合并kubeconfig文件 2 | 3 | __该项目已由 golang 重写,后续 python 版本将不再更新__,新项目地址:https://github.com/sunny0826/kubecm 4 | 5 | ## 适用环境 6 | 7 | * 需要在终端使用命令行管理多集群 8 | * kubernetes集群中安装了istio,需要使用```istioctl```命令,但是集群节点并没有安装```istioctl```,需要在本地终端操作 9 | * 不愿频繁编辑 ```.kube``` 目录中的config文件的同学 10 | 11 | ## 注意事项 12 | * 使用本脚本合并前,请先备份您您的配置文件,以免发生意外 13 | * 使用增量添加时,默认新增文件在```merge.py```同级目录,使用相对路径 14 | 15 | ## 准备工作 16 | 17 | * Python环境:2.7或者3均可 18 | * 需要依赖包:```PyYAML``` 19 | 20 | ## 快速使用 21 | 22 | * 安装依赖: 23 | 24 | pip install PyYAML 25 | 26 | * 运行脚本 27 | 28 | * 默认运行方式,kubeconfig文件放入```configfile```文件,注意删掉作为示例的两个文件 29 | 30 | python merge.py 31 | 32 | * 自定义kubeconfig文件目录 33 | 34 | python merge.py -d {custom-dir} 35 | 36 | * 向已合并的配置文件中增加新的配置,这里默认新增文件在```merge.py```同级目录,使用相对路径 37 | 38 | python merge.py -a addfilename -t tofilename 39 | 40 | ## 运行后操作 41 | 42 | * 将生成的config文件放入.kube目录中 43 | 44 | cp config ~/.kube 45 | 46 | * 查看所有的可使用的kubernetes集群角色 47 | 48 | kubectl config get-contexts 49 | 50 | * 更多关于kubernetes配置文件操作 51 | 52 | kubectl config --help 53 | 54 | * 切换kubernetes配置 55 | 56 | kubectl config use-context {your-contexts} 57 | 58 | ## 2019-04-28 更新内容 59 | 新增增量合并,在已使用本脚本合并后的 kubeconfig 后,可以使用 ```-a addfilename -t tofilename``` 参数将新的配置合并到原来已经合并好的文件中 60 | 61 | 62 | ## 问题反馈 63 | 64 | * 直接提 issue 65 | * 个人博客 https://blog.maoxianplay.com 上面有联系方式 66 | * 邮箱: sunnydog0826@gmail.com 67 | 68 | ## 代码许可 69 | 70 | MIT许可证,参见LICENSE文件。 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### macOS template 3 | # General 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | .idea/ 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | ### Python template 31 | # Byte-compiled / optimized / DLL files 32 | __pycache__/ 33 | *.py[cod] 34 | *$py.class 35 | 36 | # C extensions 37 | *.so 38 | 39 | # Distribution / packaging 40 | .Python 41 | build/ 42 | develop-eggs/ 43 | dist/ 44 | downloads/ 45 | eggs/ 46 | .eggs/ 47 | lib/ 48 | lib64/ 49 | parts/ 50 | sdist/ 51 | var/ 52 | wheels/ 53 | *.egg-info/ 54 | .installed.cfg 55 | *.egg 56 | MANIFEST 57 | 58 | # PyInstaller 59 | # Usually these files are written by a python script from a template 60 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 61 | *.manifest 62 | *.spec 63 | 64 | # Installer logs 65 | pip-log.txt 66 | pip-delete-this-directory.txt 67 | 68 | # Unit test / coverage reports 69 | htmlcov/ 70 | .tox/ 71 | .coverage 72 | .coverage.* 73 | .cache 74 | nosetests.xml 75 | coverage.xml 76 | *.cover 77 | .hypothesis/ 78 | .pytest_cache/ 79 | 80 | # Translations 81 | *.mo 82 | *.pot 83 | 84 | # Django stuff: 85 | *.log 86 | local_settings.py 87 | db.sqlite3 88 | 89 | # Flask stuff: 90 | instance/ 91 | .webassets-cache 92 | 93 | # Scrapy stuff: 94 | .scrapy 95 | 96 | # Sphinx documentation 97 | docs/_build/ 98 | 99 | # PyBuilder 100 | target/ 101 | 102 | # Jupyter Notebook 103 | .ipynb_checkpoints 104 | 105 | # pyenv 106 | .python-version 107 | 108 | # celery beat schedule file 109 | celerybeat-schedule 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | 136 | .idea/* 137 | -------------------------------------------------------------------------------- /merge.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | # Author: guoxudong 4 | """ 5 | Author: guoxudong 6 | Time: 2019-03-15 7 | UpdateTime: 2019-04-28 8 | 9 | This script is used to merge the file of kubeconfig 10 | Before using it, you should make sure your python has package: PyYAML 11 | Install it: pip install PyYAML 12 | 13 | --- 14 | 这个脚本用于合并多个kubeconfig文件,用于在一台终端操作多个kubernetes集群 15 | 需要提前安装的Python包:PyYAML 16 | 安装:pip install PyYAML 17 | 18 | 2019-04-28 更新内容: 19 | 新增增量合并,在已使用本合并后的 kubeconfig 后,可以使用 ```-a addfilename -t tofilename``` 参数将新的配置合并到原来已经合并好的文件中 20 | 21 | --- 22 | Before Usage: 23 | 1. Install package PyYAML 24 | 2. Set your infomation at the top of the scripts 25 | 26 | --- 27 | 使用之前: 28 | 1. 安装PyYAML包 29 | 2. 可以传入参数 -d kubeconfig文件所在的目录 30 | 31 | --- 32 | Usage: 33 | Select directory: 34 | python merge.py -d configfile 35 | 36 | add new config: 37 | python merge.py -a addfilename -t tofilename 38 | 39 | --- 40 | 使用: 41 | 自定义选择目录 42 | python merge.py -d configfile 43 | 44 | 向已合并的配置文件中增加新的配置 45 | python merge.py -a addfilename -t tofilename 46 | 47 | """ 48 | import argparse 49 | import json 50 | import os 51 | 52 | import yaml 53 | 54 | FLAGS = None 55 | 56 | KUBECONFIG = { 57 | "kind": "Config", 58 | "apiVersion": "v1", 59 | "preferences": {}, 60 | "clusters": [], 61 | "users": [], 62 | "contexts": [], 63 | "current-context": "" 64 | } 65 | 66 | ALLCONTEXTS = [] 67 | 68 | 69 | class ToException(Exception): 70 | def __init__(self, err='请选择源配置文件'): 71 | Exception.__init__(self, err) 72 | 73 | 74 | class AddException(Exception): 75 | def __init__(self, err='请选择配置文件'): 76 | Exception.__init__(self, err) 77 | 78 | 79 | def getLocalDirectory(): 80 | """ 81 | Process local directory 82 | 获取目录地址 83 | :param dir: 84 | :return: 配置文件目录路径 85 | """ 86 | return os.path.dirname(os.path.realpath(__file__)) + '/' + FLAGS.directory + '/' 87 | 88 | 89 | def getLocalFile(filename): 90 | """ 91 | Process local files 92 | 获取文件地址 93 | :param dir: 94 | :return: 配置文件路径 95 | """ 96 | return os.path.dirname(os.path.realpath(__file__)) + '/' + filename 97 | 98 | 99 | def addConfig(): 100 | """ 101 | 增加配置文件 102 | :return: 103 | """ 104 | add_path = getLocalFile(FLAGS.add) 105 | to_path = getLocalFile(FLAGS.to) 106 | handleAddConfig(add_path, to_path) 107 | 108 | 109 | def loadYamlFile(path): 110 | """ 111 | 读取yaml文件 112 | :param path: 113 | :return: 114 | """ 115 | with open(path, 'r') as f: 116 | return yaml.load(f.read(), Loader=yaml.FullLoader) 117 | 118 | 119 | def handleAddConfig(addfile, oldconfig): 120 | """ 121 | 处理增加配置 122 | :return: 123 | """ 124 | add_config = loadYamlFile(addfile) 125 | to_config = loadYamlFile(oldconfig) 126 | add_content = handleYaml(add_config, FLAGS.add.split('/')[-1]) 127 | to_config['clusters'].extend(add_content.get('clusters', '')) 128 | to_config['users'].extend(add_content.get('users', '')) 129 | to_config['contexts'].extend(add_content.get('contexts', '')) 130 | KUBECONFIG['clusters'] = to_config['clusters'] 131 | KUBECONFIG['users'] = to_config['users'] 132 | KUBECONFIG['contexts'] = to_config['contexts'] 133 | 134 | 135 | def readFiles(curPath): 136 | """ 137 | 读取文件 138 | :return: 139 | """ 140 | fileList = os.listdir(curPath) 141 | for filename in fileList: 142 | handleConfig(curPath + filename, filename) 143 | 144 | 145 | def handleYaml(c, filename): 146 | """ 147 | 处理yaml 148 | :param content: yaml内容 149 | :param filename: 文件名称 150 | :return: 151 | """ 152 | for i, context in enumerate(c.get('contexts', '')): 153 | cluster = context['context']['cluster'] 154 | user = context['context']['user'] 155 | name = filename + '-' + str(i) 156 | context['name'] = name 157 | ALLCONTEXTS.append(name) 158 | 159 | for clu in c.get('clusters', ''): 160 | if cluster == clu['name']: 161 | cluster_name = name + '-cluster' 162 | clu['name'] = cluster_name 163 | context['context']['cluster'] = cluster_name 164 | 165 | if len(c.get('clusters')) > len(c.get('users')): 166 | user_name = name + '-user' 167 | c['users'][0]['name'] = user_name 168 | context['context']['user'] = user_name 169 | else: 170 | for usr in c.get('users', ''): 171 | if user == usr['name']: 172 | user_name = name + '-user' 173 | usr['name'] = user_name 174 | context['context']['user'] = user_name 175 | 176 | return c 177 | 178 | 179 | def handleConfig(path, filename): 180 | """ 181 | 处理配置 182 | :param path: 配置文件路径 183 | :return: 184 | """ 185 | with open(path, 'r') as f: 186 | all = yaml.load(f.read(), Loader=yaml.FullLoader) 187 | result = handleYaml(all, filename) 188 | KUBECONFIG['clusters'].extend(result.get('clusters', '')) 189 | KUBECONFIG['users'].extend(result.get('users', '')) 190 | KUBECONFIG['contexts'].extend(result.get('contexts', '')) 191 | 192 | 193 | def outputFile(): 194 | """ 195 | 输出文件 196 | :return: 197 | """ 198 | with open('config', 'w') as f: 199 | f.write(json.dumps(KUBECONFIG)) 200 | 201 | 202 | def main(): 203 | """ 204 | 主方法 205 | :return: 206 | """ 207 | if FLAGS.add != '' and FLAGS.to == '': 208 | raise ToException 209 | elif FLAGS.add == '' and FLAGS.to != '': 210 | raise AddException 211 | elif FLAGS.add != '' and FLAGS.to != '': 212 | addConfig() 213 | print('开始') 214 | else: 215 | readFiles(getLocalDirectory()) 216 | outputFile() 217 | print('# COPY configfile to .kube:') 218 | print('cp config ~/.kube\n') 219 | print('# View all users:') 220 | print('kubectl config get-contexts\n') 221 | print('# learn more:') 222 | print('kubectl config --help\n') 223 | print('# Cluster switching command:') 224 | for command in ALLCONTEXTS: 225 | print('kubectl config use-context {0}'.format(command)) 226 | # print(ALLCONTEXTS) 227 | 228 | 229 | if __name__ == '__main__': 230 | parser = argparse.ArgumentParser() 231 | parser.add_argument( 232 | "-d", 233 | "--directory", 234 | dest="directory", 235 | default="configfile", 236 | type=str, 237 | help="the directory kubeconfig!") 238 | parser.add_argument( 239 | "-t", 240 | "--to", 241 | dest="to", 242 | default="", 243 | type=str, 244 | help="the kubeconfig that need to join the configured file!") 245 | parser.add_argument( 246 | "-a", 247 | "--add", 248 | dest="add", 249 | default="", 250 | type=str, 251 | help="add new config to kubeconfig!") 252 | FLAGS, unparsed = parser.parse_known_args() 253 | main() 254 | --------------------------------------------------------------------------------