zoukankan      html  css  js  c++  java
  • 五.运维平台之发布系统

     一.需求分析:

     

     

     

     

     

     一发布系统申请上线

    1.后端:

    (1).apps/release/models.py:

    python36env) [vagrant@CentOS devops]$ django-admin startapp release
    (python36env) [vagrant@CentOS devops]$ mv release apps/
    (python36env) [vagrant@CentOS devops]$ python manage.py makemigrations release
    (python36env) [vagrant@CentOS devops]$ python manage.py migrate release

    (2).release/views.py

    from django.contrib.auth import get_user_model
    from rest_framework import viewsets, permissions, status
    from rest_framework.response import Response
    from rest_framework.pagination import PageNumberPagination
    from rest_framework import filters
    from rest_framework.authentication import BasicAuthentication, SessionAuthentication
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    
    
    from .serializers import DeploySerializer
    from .models import Deploy
    from time import sleep
    
    User = get_user_model()
    
    
    class Pagination(PageNumberPagination):
        page_size = 10
        page_size_query_param = 'page_size'
        page_query_param = "page"
        max_page_size = 100
    
    
    class DeployViewset(viewsets.ModelViewSet):
        """
        create:
        申请上线
        list:
        获取上线列表
        retrieve:
        获取上线信息
        update:
        代码更新信息
        delete:
        取消上线
        """
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication, BasicAuthentication)
        permission_classes = (permissions.IsAuthenticated, permissions.DjangoModelPermissions)
        queryset = Deploy.objects.all()
        serializer_class = DeploySerializer
        pagination_class = Pagination
        filter_backends = (filters.SearchFilter, filters.OrderingFilter)
        search_fields = ('name',)
        ordering_fields = ('apply_time', 'deploy_time')
    
        def get_queryset(self):
            rate = self.request.GET.get('status', None)
            applicant = self.request.user
            role = applicant.groups.all().values('name')
            role_name = [r['name'] for r in role]
            queryset = super(DeployViewset, self).get_queryset()
    
            # 判断传来的status值判断是申请列表还是历史列表
            if rate and int(rate) <= 2:
                queryset = queryset.filter(status__lte=2)
            elif rate and int(rate) > 2:
                queryset = queryset.filter(status__gte=2)
            else:
                pass
    
            # 判断登陆用户是否是管理员,是则显示所有项目,否则只显示自己的项目
            if "sa" not in role_name:
                queryset = queryset.filter(applicant=applicant)
            return queryset
    
        # def partial_update(self, request, *args, **kwargs):
        #     pk = kwargs.get("pk")
        #     data = request.data
        #     data['assign_to'] = request.user
        #     print(data)
        #     if int(data['status']) == 3:
        #         print("1111")
        #         jenkins = JenkinsApi()
        #         number = jenkins.get_next_build_number(data['name'])
        #         jenkins.build_job(data['name'], parameters={'tag': data['version']})
        #         sleep(30)
        #         console_output = jenkins.get_build_console_output(data['name'], number)
        #         data['console_output'] = console_output
        #     Deploy.objects.filter(pk=pk).update(**data)
        #     return Response(status=status.HTTP_204_NO_CONTENT)

    (3).release/serializers.py

    from rest_framework import serializers
    from django.contrib.auth import get_user_model
    from .models import Deploy
    
    User = get_user_model()
    
    
    class DeploySerializer(serializers.ModelSerializer):
        """
        工单序列化类
        """
        # 获取当前登陆用户,并将其赋值给数据库中对应的字段
        applicant = serializers.HiddenField(
            default=serializers.CurrentUserDefault())
        apply_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
        complete_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
    
        class Meta:
            model = Deploy
            fields = "__all__"
    
        def to_representation(self, instance):
            applicant_obj = instance.applicant
            reviewer_obj = instance.reviewer
            assign_to_obj = instance.assign_to
            status_value = instance.get_status_display()
            ret = super(DeploySerializer, self).to_representation(instance)
            ret['status'] = {
                "id": instance.status,
                "name": status_value
            }
            ret["applicant"] = {
                                   "id": applicant_obj.id,
                                   "name": applicant_obj.name
                               },
            ret["reviewer"] = {
                                   "id": reviewer_obj.id,
                                   "name": reviewer_obj.name
                               },
    
            if assign_to_obj:
                ret["assign_to"] = {
                                       "id": assign_to_obj.id,
                                       "name": assign_to_obj.name
                                   },
            return ret

    (4).release/route.py

    from rest_framework.routers import DefaultRouter
    from .views import DeployViewset
    
    deploy_router = DefaultRouter()
    deploy_router.register(r'deploy', DeployViewset, basename="deploy")

    (5).release/task.py

    (6).devops/urls.py

    from django.conf.urls import url, include
    from rest_framework_jwt.views import obtain_jwt_token
    from rest_framework.routers import DefaultRouter
    from rest_framework.documentation import include_docs_urls
    from groupUsers .views import GroupUsersViewset
    from users.router import router as user_router
    from workorder.router import workorder_router
    from devops.settings import STATIC_ROOT
    from release.router import deploy_router
    from groups.router import group_router
    from permissions.router import permission_router
    from groupUsers.router import groupuser_router
    from resources.router import router as resources_router
    
    router = DefaultRouter()
    router.registry.extend(user_router.registry)
    router.registry.extend(workorder_router.registry)
    router.registry.extend(group_router.registry)
    router.registry.extend(groupuser_router.registry)
    router.registry.extend(permission_router.registry)
    router.registry.extend(deploy_router.registry)
    
    urlpatterns = [
        url(r'^api/', include(router.urls)),
        url(r'^', include('resources.urls')),
        url(r'^api-auth/', include('rest_framework.urls')),
        url(r'^docs/', include_docs_urls("51reboot接口文档")),
        url('^projects/', include('projects.urls', namespace='projects')),
        url(r'^api-token-auth/', obtain_jwt_token),
    ]

    (7).apps/utils/jenkins_api.py

    import gitlab
    
    from devops.settings import GITLAB_HTTP_URI, GITLAB_TOKEN
    gl = gitlab.Gitlab(GITLAB_HTTP_URI, GITLAB_TOKEN)
    
    def get_user_projects(request):
        """
        获取gitlab里所有的项目,和登录用户所拥有的项目,以及登录用户所拥有项目的项目成员
        :return: []
        """
        user_projects = []
        all_projects = gl.projects.list()
        print(request.user.username)
        print(all_projects)
    
        # 获取当前用户所有的项目
        for project in all_projects:
            print(project)
            for member in project.members.list():
                # if member.username == request.user.username:
                if member.username == "root":
                    user_projects.append(project)
        print(user_projects)
        return user_projects
    
    
    def get_project_versions(project_id):
        """
        获取某个项目的版本号
        :param project_id:
        :return:
        """
        project = gl.projects.get(project_id)
        tags = project.tags.list()
        print(tags)
        return tags

    效果如图:

    2.前端

    (1)src/api/release/release.js

    import request from '@/utils/request'
    
    // 获取申请列表
    export function getDeployList(params) {
      return request({
        url: '/api/deploy/',
        method: 'get',
        params
      })
    }
    
    // 申请项目上线
    export function createDeploy(data) {
      return request({
        url: '/api/deploy/',
        method: 'post',
        data
      })
    }
    
    // 更新项目
    export function updateDeploy(id, data) {
      return request({
        url: '/api/deploy/' + id + '/',
        method: 'patch',
        data
      })
    }

    (2)src/router/index.js

      {
        path: '/release',
        component: Layout,
        name: '代码上线',
        meta: { title: '代码上线', icon: 'user' },
        children: [
          {
            path: 'apply',
            name: '申请上线',
            component: () => import('@/views/release/apply/index'),
            meta: { title: '申请上线', icon: 'user' }
          },
          {
            path: 'list',
            name: '申请列表',
            component: () => import('@/views/release/list/index'),
            meta: { title: '申请列表', icon: 'tree' }
          },
          {
            path: 'history',
            name: '上线列表',
            component: () => import('@/views/release/history/index'),
            meta: { title: '上线列表', icon: 'tree' }
          }
        ]
      },

    (3)views/release/apply/index.vue

    <template>
      <div class="apply">
        <el-form ref="form" :model="form" :rules="rules" label-width="180px">
          <el-form-item label="选择项目:" prop="name">
            <el-select v-model="form.name" placeholder="请选择项目类型" style=" 60%;" @change="getTag">
              <el-option
                v-for="item in project_list"
                :key="item.index"
                :label="item.name"
                :value="item.name"/>
            </el-select>
          </el-form-item>
    
          <el-form-item label="项目版本:" prop="version">
            <el-select v-model="form.version" value-key="label" placeholder="请选择项目版本" style=" 60%;" @change="getTaginfo">
              <el-option
                v-for="item in tag_list"
                :key="item.index"
                :label="item.name"
                :value="item.name"/>
            </el-select>
          </el-form-item>
    
          <el-form-item label="版本信息:" prop="info">
            <el-input v-model="form.info" style=" 60%;"/>
          </el-form-item>
    
          <el-form-item label="指派给:" prop="assign_to">
            <el-select v-model="form.reviewer" filterable placeholder="请选择项目处理人" style=" 60%;">
              <el-option
                v-for="item in sa_list"
                :key="item.index"
                :label="item.name"
                :value="item.id"/>
            </el-select>
          </el-form-item>
    
          <el-form-item label="上线详情:" prop="detail">
            <el-input :rows="8" v-model="form.detail" type="textarea"  style=" 60%;"/>
          </el-form-item>
    
          <el-form-item>
            <el-button type="primary" @click="onSubmit">申请上线</el-button>
          </el-form-item>
        </el-form>
      </div>
    </template>
    
    <script>
    
    import { getGroupMemberList } from '@/api/group'
    import { getProjectList, getProjectTag } from '@/api/project/project'
    import { createDeploy } from '@/api/release/release'
    export default {
      data() {
        return {
          form: {
            name: '',
            version: '',
            info: '',
            detail: '',
            reviewer: ''
          },
          rules: {
            name: [
              { required: true, message: '请输入项目名称', trigger: 'blur' }
            ],
            version: [
              { required: true, message: '请输入项目版本', trigger: 'blur' }
            ],
            info: [
              { required: true, message: '请输人项目内容', trigger: 'blur' }
            ],
            reviewer: [
              { required: true, message: '请输人项目执行人', trigger: 'blur' }
            ]
    
          },
          sa_list: [],
          project_list: [],
          tag_list: [],
          state: 0
        }
      },
    
      watch: {
        state() {
          getGroupMemberList(6).then(res => {
            this.sa_list = res.members
            console.log(this.sa_list)
          })
    
          getProjectList().then(res => {
            this.project_list = res
            console.log(this.project_list)
          })
        }
    
      },
    
      created() {
        this.state = 1
      },
    
      methods: {
        /* 获取某个项目的tag列表*/
        getTag(name) {
          let obj = {}
          obj = this.project_list.find((item) => {
            return item.name === name
          })
          const params = { 'project_id': obj.id }
          getProjectTag(params).then(res => {
            this.tag_list = res
            console.log(this.tag_list)
          })
        },
        /* 跟进tag名获取message */
        getTaginfo(name) {
          let obj = {}
          obj = this.tag_list.find((item) => {
            return item.name === name
          })
          console.log(obj)
          this.form.info = obj.info
        },
        /* 申请上线 */
        onSubmit() {
          this.$refs.form.validate((valid) => {
            if (!valid) {
              return
            }
            const params = Object.assign({}, this.form)
            console.log(params)
            createDeploy(params).then(res => {
              this.$message({
                message: '申请上线成功',
                type: 'success'
              })
              this.$router.push({ path: '/release/list' })
            })
          })
        }
      }
    
    }
    </script>
    
    <style scoped>
    .line{
      text-align: center;
    }
    .apply{
        margin-top:2cm;
    }
    </style>

    (4)views/release/list/form.vue

    <template>
      <div class="deploy-form">
        <el-form ref="form" :model="form" :rules="rules" label-width="100px" class="demo-form">
    
          <el-form-item label="项目名称" prop="name">
            <el-input v-model="form.name" readonly/>
          </el-form-item>
    
          <el-form-item label="项目版本" prop="version">
            <el-input v-model="form.version" readonly/>
          </el-form-item>
    
          <el-form-item label="项目描述" prop="info">
            <el-input v-model="form.info" readonly/>
          </el-form-item>
    
          <el-form-item label="项目详情" prop="detail">
            <el-input v-model="form.detail" type="textarea" rows="8" readonly/>
          </el-form-item>
    
          <el-form-item>
            <div class="btn-wrapper">
              <el-button size="small" type="primary" @click="submitForm">下一步</el-button>
            </div>
          </el-form-item>
    
        </el-form>
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'DeployForm',
      props: {
        form: { // 接受父组件传递过来的值渲染表单
          type: Object,
          default() {
            return {
              name: '',
              info: '',
              version: '',
              detail: '',
              status: ''
            }
          }
        }
      },
    
      data() {
        return {
          rules: {
            name: [
              { required: true, message: '请输入处理结果', trigger: 'blur' }
            ]
          }
        }
      },
    
      methods: {
        submitForm() {
          this.$refs.form.validate(valid => {
            if (!valid) {
              return
            }
            this.$emit('submit', this.form)
          })
        }
      }
    }
    </script>
    
    <style lang='scss' scoped>
    .deploy-form {
      position: relative;
      display: block;
      .btn-wrapper{
        text-align: right;
      }
    }
    </style>

    (5)views/release/list/index.vue

    <template>
      <div class="release">
        <div>
          <!--搜索-->
          <el-col :span="8">
            <el-input v-model="params.search" placeholder="搜索" @keyup.enter.native="searchClick">
              <el-button slot="append" icon="el-icon-search" @click="searchClick"/>
            </el-input>
          </el-col>
        </div>
    
        <!--表格-->
        <deploy-list :value="release" @edit="handleEdit" @delete="handleDelete"/>
    
        <!--模态窗-->
        <el-dialog
          :visible.sync="dialogVisibleForEdit"
          title="上线进度"
          width="50%">
          <el-steps :active="active" finish-status="success" simple style="margin-top: 20px">
            <el-step title="申请" />
            <el-step title="审核" />
            <el-step title="灰度" />
            <el-step title="上线" />
          </el-steps>
          <br>
          <deploy-form
            ref="releaseForm"
            :form="currentValue"
            @submit="handleSubmitEdit"/>
        </el-dialog>
    
        <!--分页-->
        <center>
          <el-pagination
            :page-size="pagesize"
            :total="totalNum"
            background
            layout="total, prev, pager, next, jumper"
            @current-change="handleCurrentChange"/>
        </center>
      </div>
    </template>
    
    <script>
    import { getDeployList, updateDeploy } from '@/api/release/release'
    import DeployList from './table'
    import DeployForm from './form'
    
    export default {
      name: 'Release',
      components: {
        DeployList,
        DeployForm
      },
    
      data() {
        return {
          dialogVisibleForEdit: false,
          currentValue: {},
          release: [],
          totalNum: 0,
          pagesize: 10,
          active: 1,
          params: {
            page: 1,
            search: '',
            ordering: '-deploy_time',
            status: 0
          }
        }
      },
    
      created() {
        this.fetchData()
      },
    
      methods: {
        fetchData() {
          getDeployList(this.params).then(
            res => {
              this.release = res.results
              console.log(this.release)
              this.totalNum = res.count
            })
        },
        handleCurrentChange(val) {
          this.params.page = val
          this.fetchData()
        },
        searchClick() {
          this.fetchData()
        },
    
        /* 处理上线申请,弹出模态窗、提交数据、取消 */
        handleEdit(value) {
          this.currentValue = { ...value }
          this.dialogVisibleForEdit = true
          this.params.status = this.currentValue.status.id
          this.active = this.params.status + 1
        },
    
        handleSubmitEdit(value) {
          const { id, ...params } = value
          console.log(params)
          const formdata = { 'status': this.params.status + 1, 'name': params.name, 'version': params.version }
          updateDeploy(id, formdata).then(res => {
            this.$message({
              message: '更新成功',
              type: 'success'
            })
          })
          this.fetchData()
          this.dialogVisibleForEdit = false
        },
    
        /* 取消 */
        handleDelete(id) {
          console.log(id)
          const data = { 'status': 4 }
          updateDeploy(id, data).then(res => {
            this.$message({
              message: '取消成功',
              type: 'success'
            })
            this.fetchData()
          },
          err => {
            console.log(err.message)
          })
        }
    
      }
    
    }
    </script>
    
    <style lang='scss' scoped>
    .release {
      padding: 10px;
    }
    </style>

    (6)views/release/list/table.vue

    <template>
      <div class="deploy-list">
        <el-table
          :data="value"
          border
          stripe
          style=" 100%">
    
          <el-table-column type="expand">
            <template slot-scope="props">
              <span><pre>版本描述:{{ props.row.info }}</pre></span>
              <span><pre>发布信息:{{ props.row.detail }}</pre></span>
            </template>
          </el-table-column>
    
          <el-table-column
            label="项目名称"
            prop="name"/>
    
          <el-table-column
            label="项目版本"
            prop="version"/>
    
          <el-table-column
            label="申请人"
            prop="applicant[0].name"/>
    
          <el-table-column
            label="审核人"
            prop="reviewer[0].name"/>
    
          <el-table-column
            label="状态"
            prop="status.name"/>
    
          <el-table-column
            :formatter="dateFormat"
            label="申请时间"
            prop="apply_time"
          />
    
          <el-table-column label="操作">
            <template slot-scope="scope">
              <el-button
                size="mini"
                type="primary"
                @click="handleEdit(scope.row)">处理</el-button>
    
              <el-button
                size="mini"
                type="danger"
                @click="handleDelete(scope.row)">取消</el-button>
            </template>
          </el-table-column>
    
        </el-table>
      </div>
    </template>
    
    <script>
    import moment from 'moment'
    
    export default {
      name: 'DeployList',
      props: {
        value: {
          type: Array,
          default: function() {
            return []
          }
        }
      },
      methods: {
        /* 点击编辑按钮,将子组件的事件传递给父组件 */
        handleEdit(value) {
          this.$emit('edit', value)
        },
    
        /* 删除 */
        handleDelete(value) {
          const id = value.id
          const name = value.name
          this.$confirm(`取消上线: ${name}, 是否继续?`, '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.$emit('delete', id)
          }).catch(() => {
            this.$message({
              type: 'info',
              message: '已取消删除'
            })
          })
        },
        dateFormat: function(row, column) {
          const date = row[column.property]
          if (date === undefined) {
            return ''
          }
          return moment(date).format('YYYY-MM-DD HH:mm:ss')
        }
    
      }
    }
    </script>
    
    <style lang='scss'>
    </style>

     效果如图:

     报错--前端post请求报400错误:认证失败Uncaught (in promise) Error: Request failed with status code 400

    一般是前后端交互的方法参数不一致,发生此错误需要仔细检查前端传递的参数数据的参数名、参数数目、参数类型是否与后端保持一致。

     

     

     三.Jenkins api

    jenkins部署:
    jdk安装:
    [root@VM_0_5_centos ~]#tar -zxvf jdk-8u261-linux-x64.tar.gz -C /usr/local/java/
    [root@VM_0_5_centos ~]#vi /etc/profile
    export JAVA_HOME=/usr/local/java/jdk1.8.0_261
    export JRE_HOME=${JAVA_HOME}/jre
    export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
    export PATH=${JAVA_HOME}/bin:$PATH
    [root@VM_0_5_centos ~]#source /etc/profile
    [root@VM_0_5_centos ~]# java -version
    安装配置:
    各种报错参考此文档https://www.ddkiss.com/archives/167.html
    [root@VM_0_5_centos ~]# rpm -ivh jenkins-2.99-1.1.noarch.rpm
    [root@VM_0_5_centos ~]# vi /etc/sysconfig/jenkins
    JENKINS_USER="root"JENKINS_PORT="8088"
    修改目录权限:
    [root@VM_0_5_centos ~]# chown -R root:root /var/lib/jenkins
    [root@VM_0_5_centos ~]# chown -R root:root /var/cache/jenkins
    [root@VM_0_5_centos ~]# chown -R root:root /var/log/jenkins
    
    [root@VM_0_5_centos ~]# vi /etc/init.d/jenkins
    第一个java路径就是我自己加的!
    candidates="
    /usr/local/java/jdk1.8.0_261/bin/java
    /etc/alternatives/java
    /usr/lib/jvm/java-1.8.0/bin/java
    /usr/lib/jvm/jre-1.8.0/bin/java
    /usr/lib/jvm/java-1.7.0/bin/java
    /usr/lib/jvm/jre-1.7.0/bin/java
    /usr/bin/java
    "
    [root@VM_0_5_centos ~]# systemctl start jenkins
    [root@VM_0_5_centos ~]# systemctl status jenkins
    放通腾讯云服务器8088端口:
    (1)进入控制台页面-->安全组--->添加安全组

    (2)点击刚创建的规则id--点关联实例---新增关联

     

     这就就可直接在你windows机器访问腾讯云的jenkins服务了!!如下图:

     jenkins要安装Git Parameter插件---支持参数化构建。如下图

     

     

     2.jenkins api使用

    (python36env) [vagrant@CentOS devops]$ pip install python-jenkins
    python36env) [vagrant@CentOS devops]$ ipython
    In [1]: import jenkins                                                     
    In [2]: JENKINS_URL = "http://120.53.122.**:8088"                          
    In [3]: JENKINS_USERNAME = 'root'                                          
    In [4]: JENKINS_PASSWORD = '181818jn'                                      
    In [5]: server = jenkins.Jenkins(JENKINS_URL, username = JENKINS_USERNAME, 
       ...: password = JENKINS_PASSWORD)                                       
    In [6]: server.get_job_info("51reboot") 
    In [9]:server.build_job("51reboot1", parameters={'tag': "version1.0"}) 
    In [10]: server.build_job("51reboot1", parameters={'tag': "version1.1"})

    In [13]: server.get_build_console_output("51reboot1", 2) 

    In [14]: server.get_job_info('51reboot1')['nextBuildNumber']
    Out[14]: 3

    (1)devops/settings.py:

    JENKINS_URL = "http://120.53.122.**:8088"
    JENINS_TOKEN = "9b6bd371a9ba47511a0f04184e1076df"
    JENKINS_USERNAME = 'root'
    JENKINS_PASSWORD = '18181**'

    (2)apps/utils/jenkis_api.py:

    from jenkins import Jenkins
    from devops.settings import JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD
    
    
    class JenkinsApi:
        def __init__(self):
            self.url = JENKINS_URL
            self.username = JENKINS_USERNAME
            self.password = JENKINS_PASSWORD
            self.server = self.connect()
    
        def connect(self):
            """
            连接jenkins(实例化jenkins)
            :return:
            """
            server = Jenkins(self.url, username=self.username, password=self.password)
            return server
    
        def get_next_build_number(self, name):
            """
            获取下一次构建号
            :param name: 任务名称(项目名称)
            :return: "int" number
            """
            return self.server.get_job_info(name)['nextBuildNumber']
    
        def build_job(self, name, parameters=None):
            """
            构建任务
            :param name: "str" 任务名称
            :param parameters: "dict" 参数
            :return: "int" queue number
            """
            return self.server.build_job(name=name, parameters=parameters)
    
        def get_build_console_output(self, name, number):
            """
            获取终端输出结果
            :param name: "str" 任务名称
            :param number: "str" 构建号
            :return: "str" 结果
            """
            return self.server.get_build_console_output(name, number)

     (3)apps/release/views.py:

    from utils.jenkins_api import JenkinsApi
    from .serializers import DeploySerializer
    from .models import Deploy
    from time import sleep
    
    User = get_user_model()
    
    class Pagination(PageNumberPagination):
        page_size = 10
        page_size_query_param = 'page_size'
        page_query_param = "page"
        max_page_size = 100
    
    class DeployViewset(viewsets.ModelViewSet):
       .......
        def partial_update(self, request, *args, **kwargs):
            pk = kwargs.get("pk")
            data = request.data
            data['assign_to'] = request.user
            print(data)
            if int(data['status']) == 3:
                print("1111")
                jenkins = JenkinsApi()
                number = jenkins.get_next_build_number(data['name'])
                jenkins.build_job(data['name'], parameters={'tag': data['version']})
                sleep(30)
                console_output = jenkins.get_build_console_output(data['name'], number)
                data['console_output'] = console_output
            Deploy.objects.filter(pk=pk).update(**data)
            return Response(status=status.HTTP_204_NO_CONTENT)

    效果如图:

     四.部署

     参考:https://segmentfault.com/a/1190000004232816--如下说明

     

    (1)devops/settings.py:

    DEBUG = False
    ALLOWED_HOSTS = ["*"]
    
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, "static/")

    (2)devops/urls.py:

    from django.views.static import serve
    from restfuldemo.settings import STATIC_ROOT
    
    urlpatterns = [
        url(r'^api/', include(router.urls)),
        url(r'^', include('resources.urls')),
        url(r'^api-auth/', include('rest_framework.urls')),
        url(r'^docs/', include_docs_urls("51reboot接口文档")),
        url('^projects/', include('projects.urls', namespace='projects')),
        url(r'^login/', obtain_jwt_token),
        url(r'^api-token-auth/', obtain_jwt_token),
        url(r'^static/(?P<path>.*)$', serve, {"document_root": STATIC_ROOT}),
    ]
    (3)(python36env) [vagrant@CentOS devops]$ ls
    apps  dashboard  devops  manage.py
    (python36env) [vagrant@CentOS devops]$ mkdir static
    (python36env) [vagrant@CentOS devops]$ ./manage.py collectstatic
    (python36env) [vagrant@CentOS devops]$ ls static/
    admin  rest_framework

    这样就能正常访问了,如下图:

     

    (4)gunicorn部署:
    (python36env) [vagrant@CentOS devops]$ pip install -U gunicorn
    (python36env) [vagrant@CentOS devops]$ gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009
    [2020-07-26 07:03:54 +0200] [4300] [INFO] Using worker: sync
    [2020-07-26 07:03:54 +0200] [4303] [INFO] Booting worker with pid: 4303.......
    (python36env) [vagrant@CentOS devops]$ gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009 -D
    (python36env) [vagrant@CentOS devops]$ ps -ef|grep gun
    //(python36env) [vagrant@CentOS devops]$ killall gunicorn

    报错:ERR_CONNECTION_REFUSED

    (python36env) [vagrant@CentOS devops]$ curl 127.0.0.1:8009/api/
    {"detail":"身份认证信息未提供。"}

    (5)devops/conf/devops_nginx.conf

    upstream django {
        # server unix:///path/to/your/mysite/mysite.sock; # for a file socket
        server 127.0.0.1:8004; # for a web port socket (we'll use this first)
    }
    # configuration of the server
    
    server {
        listen      80;
        server_name 127.0.0.1;
        # 指向django的static目录
        location /static {
            alias /vagrant/devops/devops/static;
        }
        location / {
            uwsgi_pass 127.0.0.1:8009;
            include uwsgi_params;
        }
        error_log /tmp/devops8_error.log;
        access_log /tmp/devops8_access.log;
    }

    (6)devops/conf/devops_uwsgi.ini

    [uwsgi]
    
    # Django-related settings
    # the base directory (full path)
    chdir           = /vagrant/devops/devops
    # Django's wsgi file
    module          = devops.wsgi
    # the virtualenv (full path)
    
    # process-related settings
    # master
    master          = true
    # maximum number of worker processes
    processes       = 10
    # the socket (use the full path to be safe
    socket          = 0.0.0.0:8009
    # ... with appropriate permissions - may be needed
    # chmod-socket    = 664
    # clear environment on exit
    vacuum          = true
    virtualenv = /home/vagrant/python36env
    
    # pid file path
    pidfile         = /tmp/devops.pid
    # background process and specify the log file
    daemonize       = /tmp/devops.log
    # log file max size(KB)
    log-maxsize     = 50000000
    (python36env) [vagrant@CentOS devops]$pip install uwsgi
    (python36env) [vagrant@CentOS devops]$ ps -ef|grep gun
    vagrant   4579     1  1 08:05 ?        00:00:00 /home/vagrant/python36env/bin/python /home/vagrant/python36env/bin/gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009 -D
    vagrant   4582  4579 17 08:05 ?        00:00:01 /home/vagrant/python36env/bin/python /home/vagr
    (python36env) [vagrant@CentOS devops]$ kill -HUP 4579
    (python36env) [vagrant@CentOS devops]$ ps -ef|grep gun
    vagrant   4579     1  0 08:05 ?        00:00:00 /home/vagrant/python36env/bin/python /home/vagrant/python36env/bin/gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009 -D
    (python36env) [vagrant@CentOS devops]$ cd conf
    (python36env) [vagrant@CentOS conf]$ ls
    devops_nginx.conf  devops_uwsgi.ini
    (python36env) [vagrant@CentOS conf]$ uwsgi -i devops_uwsgi.ini
    (python36env) [vagrant@CentOS conf]$ ps -ef|grep 8009

    1

    2

    3

  • 相关阅读:
    Angularjs中的ng-class
    AngularJS 的表单验证
    Eclipse更新慢、插件安装慢解决方案zz
    PSD的单位及计算方法[转]
    .NET控件名称缩写一览表 zz
    C#Stopwatch的简单计时zz
    VsVim的快捷键
    MySQL-mysql 8.0.11安装教程
    使用open live writer客户端写博客zz
    WPFToolkit DataGrid 使用介绍zz
  • 原文地址:https://www.cnblogs.com/dbslinux/p/13358815.html
Copyright © 2011-2022 走看看