반응형

     

<프로그램 실행 화면 - cmd 환경>

이번 포스팅에서는 Services 내 jenkins 서비스를 찾아 Status 를 Stop 으로 하고 나서,  특정 폴더 내 폴더들 및 파일들을 찾아 삭제를 하는 FolderControlCore 코드를 확인 해 본다.

Main Code - 1
Main Code - 2

1. Service (0) 을 던져, 서비스를 멈추고 나서 foreach 를 실행한다. 이때 deleteFolderName 은 스트링 배열로, Main code 에 다음과 같이 선언되어 있다. 

Main Code -3

2. 배열 갯수만큼 foreach 가 돌면서 folderName 이 하나씩하나씩 클래스 멤버로 설정이 되며, SearchAndDeleteFolders() 메소드를 실행 시킨다. - 예) lastStable

FolderControlCore - SearchAndDeleteFolders()

3. SearchAndDeleteFolders() 메소드 는 설정된 directoryName 으로 폴더를 우선 찾아본다. SearchDirectories() 의 결과를  folderFound 변수에 담아 Count 확인 후, DeleteDirectories() 를 호출한다.

FolderControlCore - SearchDirectories&nbsp;()

4. SearchDirectories() 메소드는 .Net 에서 지원하는 Directory 클래스 내 GetDirectoreis 메소드를 사용하여 검색한다. 이때 특정 폴더 (upperDirectoryName = %Jenkins HOME% ) 와 지울 폴더 (예) lastStable) 가 있는지 검색 하여 검색 결과를 IEnumerable<string> folderFound 로 전달한다.

FolderControlCore - DeleteDirectories()

5. DeleteDirectories() 메소드에서는 전달받은 폴더 경로들(list) 을 다시 한번 CheckPath() 메소드로 string 이 파일경로 형태의 string 포멧인지를 확인한다. CheckPath() 는 True/False 값을 넘기며, 경로확인이 되었을 때 .net framework 에서 지원하는 Directory 클래스의 Delete() 메소드를 이용하여 경로(path)를 삭제한다.

FolderControlCore - CheckPath()

6. CheckPath() 는 정규 표현식으로 path 문자열을 확인 한다. .net framework 내 Regex 클래스의 IsMatch 메서드는 지정된 패턴과 경로 문자열이 일치하는지 확인하며, 일치하는 경우 메서드는 true를 반환하고, 그렇지 않은 경우 false를 반환한다.

  • ^는 문자열의 시작을 나타냄
  • (([a-zA-Z]:)|(\))는 드라이브 문자와 : 또는 단일 백슬래시()와 일치하는지 확인
  • (\{1}|((\{1})^\)+)는 나머지 경로를 일치시키며, 백슬래시() 다음에는 , :, *, ?, <, >, ", |가 아닌 문자열의 시퀀스가 와야 하며, 이 패턴은 여러 번 반복 가능하다.

7. 각 폴더별 (예: lastStable ) 로 찾은 폴더 갯수 및 삭제한 폴더 갯수, 그리고 지워지지 않은 폴더 갯수를 로그파일에 남긴다. 갯수 위에는 폴더 경로들이 찍히며, 총 4번이 찍히게 된다.

삭제 결과로그

이렇게 foreach() loop 이 완료되면 ServiceControlCore 의 메소드인 ControlService(1) 을 호출하여 Jenkins 서비스를 재시작한다.

사실 현재 사용하는 프로그램에 대한 설명은 완료 되었지만, Jenkins 서비스를 강제 shutdown 시키는 방법보다는 safe-shutdown 시키는 방법을 권장 된다. 이 방법은 Jenkins 내 shutdown 명령어가 적용 될 때, 실행 시작이 된 프로세스가 있는지 확인 하며, 완료 후 shutdown 실행이 되는데, 이 방법을 사용하려면 프로그램 안에서 cmd 명령어를 실행 시켜 진행한다. 다음 포스팅에서 이부분에 대해 알아보려고 한다.

-끝-

youp-han/Jenkins-Restart: it restarts the running Jenkins Service locally (github.com)

 

GitHub - youp-han/Jenkins-Restart: it restarts the running Jenkins Service locally

it restarts the running Jenkins Service locally. Contribute to youp-han/Jenkins-Restart development by creating an account on GitHub.

github.com

 

반응형
반응형

Tool 개발 로그 - 1-1 #Jenkins #서비스 #재시작 + @작업하는 #Tool 만들기 c# -배경 #시나리오

 

Tool 개발 로그 - 1-1 #Jenkins #서비스 #재시작 + @작업하는 #Tool 만들기 c# -배경 #시나리오

* 2020년 9월에 작성 된 Tool의 개발 로그입니다. 회사에서 사용하고 있는 Jenkins 가 간혹 이상 증상을 일으키는데, 그 중 하나는 Windows OS 를 사용하는 Slave-node 들이 모두 off-line 으로 변경 된다. - 참

yobine.tistory.com

* 2020년 9월에 작성 된 Tool의 개발 로그, 2번째 프로그램 작성 ServiceControlCore 설명이다. 

- Windows OS 내 Services (서비스) 툴에 등록 된 서비스 를 멈추고 시작하고, 상태를 확인할 때, 유용하게 사용할 수 있도록 제공 된 닷넷 클래스가 있다. 이름은 ServiceController 이며 이에 대한 상세 설명은 다음 링크에 기록되어 있다. -  https://learn.microsoft.com/ko-kr/dotnet/api/system.serviceprocess.servicecontroller?view=dotnet-plat-ext-7.0

 

ServiceController 클래스 (System.ServiceProcess)

Windows 서비스를 나타내며 이 클래스를 사용하면 실행 중이거나 중지된 서비스에 연결하거나 서비스를 조작하거나 서비스 관련 정보를 가져올 수 있습니다.

learn.microsoft.com

이 클래스를 사용하여 서비스 상태를 가지고 오고, 멈춘 뒤, 필요한 작업을 진행 하고, 마지막에 서비스를 다시 시작한다. 해당 프로그램의 배경 시나리오 포스트( https://yobine.tistory.com/582 ) 에서 작성 된 프로그램의 전체 플로우와 동일하다. 

Main

이번 포스팅에서는 ServiceControlCore 클래스 내 있는 Method 들을 살펴 본다. 상단에 언급했듯 이 ServiceControlCore 클래스 에서는 닷넷에서 제공하는 ServiceController 클래스를 사용하여 Jenkins 서비스의 상태를 확인하고 변경한다.

프로그램에서 제일 처음에 호출 하는 작업이 GetServices() 메소드 이다. 

이 메소드는 Jenkins 서비스 상태를 확인하는 부분인데, 리턴 값은 bool 이며. 선언된 serviceName (Jenkins) 과 Services[] 로 받아온 리스트를 비교 하여, ServiceName 이 리스트에 있는지 우선 확인 하며, 서비스 이름이 Services 에 등록되어 있다면 현재 상태를 확인 하고, running 인 경우 true 를 반환한다. 

services 에 등록된 service 리스트
Services 리스트에서 검색 매치된 Jenkins
- GetService() 메소드 - 뭔가 많아 보이지만, result = true 로 바뀌는 부분만 중요하며, 나머지는 로그 관련 스트링 전달문들이다.

- 서비스가 언제나 running 인 상태여야 프로그램이 돌기 때문에, 이부분에 대해 수정이 필요할 것 같다. 

더보기

* 서비스 이름은 검색이 안되는 경우를 빼고는 해당 서비스의 상태가 stopped 인 경우에도 프로그램이 돌아야 한다. 이부분은 수정 되어야 할 사항이다. 아마 수정이 된다면, 다음 표의 내용 처럼 리턴 값을 받아 간단하게 수정이 될 수 있을 것 같다.

서비스 등록여부 서비스 상태 리턴 값
true (등록) running 11 : (true 1, running 1)
true (등록) stopped 10 : (true 1, stopped 0)
false (등록안됨) stopped 20 : (false 2, stopped 0)

 

다음은 ControlService() 메소드 다. 이 메소드에서 서비스를 실질적으로 멈추고, 시작한다. 우선 int flag 를 인자로 , 0은 서비스 멈춤 (Stop), 1은 서비스 시작 (Start) 으로 약속된 값을 전달 받는다. 실행 중인 Jenkins 서비스(serviceName )를 멈추고(Stop)  20초 timeout 시간을 걸어주는데, 서비스가 멈추는데 걸리는 시간이 대략 최대 20초 정도여서, 멈출 때까지 대기를 하지만, 대부분 20초 전에 멈추기 때문에 대기 시간으로써는 충분한 시간이다.

ControlService() Method

ControlService() 메소드 에서 flag 값에 따라 분기가 일어나는데, if/else 가 아닌 switch 문을 사용했다. 1과 0 만이 아닌 그외의 명령어 까지 전달을 생각으로 메소드를 작성했다. 내부적으로 시작 혹은 멈추는 명령어를 전달 후, 서비스 상태를 2초마다 확인하는데, 이 메소드 이름은 CheckServiceStatus(int flag) 이다. 이 메소드 는 ControlService(int flag) 메소드에서 전달 받은 동일한 인자 flag 를 받아 GetService() 메소드를 호출하여 상태를 확인 한다. 

CheckServiceStatus()

서비스를 Stop (0) 을 시켜야 하는데, GetService 의 리턴 값이 true 면, 다시 동일한 flag 값 (0) 을 가지고 재귀호출을 한다. 만약 GetSerivce 의 리턴값이 false 라면, break 가 걸리고, 서비스가 멈추었다는 로그를 남긴다. 

서비스를 Start(1) 하는 내용도 동일하다. 리턴값들이 반대이지만, 동일하게 작동한다. 

CMD 화면

해당 프로그램을 실행하면 위의 CMD 화면과 같이 화면에 로그들이 찍힌다. 처음에 Jenkins 서비스를 찾았고, 실행 중인 것이 확인 되어 재시작 프로세스가 시작되었다고 나오며, 서비스를 멈추게 한다. 서비스가 멈춘 후 삭제해야 할 폴더들을 각각 찾아서 삭제를 진행 하게 되며, 작업이 끝난 후에 다시 Jenkins 서비스를 실행 한다. 

-끝-

youp-han/Jenkins-Restart: it restarts the running Jenkins Service locally (github.com)

 

GitHub - youp-han/Jenkins-Restart: it restarts the running Jenkins Service locally

it restarts the running Jenkins Service locally. Contribute to youp-han/Jenkins-Restart development by creating an account on GitHub.

github.com

 

반응형
반응형

 * 2020년 9월에 작성 된 Tool의 개발 로그입니다.

회사에서 사용하고 있는 Jenkins 가 간혹 이상 증상을 일으키는데, 그 중 하나는 Windows OS 를 사용하는 Slave-node 들이 모두 off-line 으로 변경 된다.

- 참고로 Jenkins 를 Master-Slave node 로 구성하는 내용은 다른 블로그에 많이 적혀 있으므로 여기서는 생략하며 아래 링크에 간략한 구성도 포함되어 공유한다. 

- https://velog.io/@doontagi/Jenkins-Master-Slave-%EA%B5%AC%EC%84%B1 

 

Jenkins Master / Slave 구성

젠킨스는 주로 소프트웨어 통합 서비스를 위해 사용된다. 이외에도 주기적인 빌드, 배포가 필요한 Batch Job을 수행하는데 활용될 수 있다.이 과정에서 하나의 Jenkins 인스턴스에 부하가 생길 수 있

velog.io

다시 본론으로 돌아오면,

사용 중 인 Jenkins 버전 (2.13) 버그여서, Jenkins 를 상위 버전으로 업그레이드를 하게 되면 없어지는 현상이지만, 해당 Jenkins 에 등록되어 배포 중 인 프로젝트들도 많고 (20+), 설치 된 플러그인들 중, 해당 버전의 Jenkins 에서는 잘 사용 중이지만, 상위 버전에서는 지원이 끊겨, 업데이트를 시도 했다가, 여러 문제가 발생하여 다시 현재 버전의 Jenkins 로 롤백하게 되었고, 버그 발생도 감안하며 사용 중 이다.

이 후 2.13 버전의 Jenkins 서비스엔 새로운 개발 프로젝트 등록은 하지 않기로 결정이 났고, 사용 중인 프로젝트들만 요청 시 따로 분리하는 작업을 진행 했지만 원치 않는 부서들이 더 많아서, 오류 발생 연락이 왔을 때, 바로 조치를 취해 줘야 한다.

Windows OS 를 사용하는 Slave-Node 들이 모두 off-line 으로 변경되는 오류 발생 시 취해야 하는 방법은, 인터넷 검색을 통해 다음과 같이 정리 되었다. 

  1. safeRestart : https://jenkins.url.com/safeRestart 를 실행 해 준다. CentOS 등을 사용하는 Slave-agent 들이 돌고 있을 수도 있어서 해당 agent 들의 job 이 완료되면 Jenkins 서비스 재실행이 될 수 있도록 한다. (Windows OS 의 Slave-node 로 배포 하는 프로젝트 들은 강제로 끊어줘야 한다. - 배포 job 실행 후 slave node 가 off-line 이여서 slave node 가 on-line 이 되기 를 기다리며서 job 진행 중이 되므로, safeRestart가 불가능하다. 
  2. Jenkins 서비스가 멈춘 뒤, 재시작이 진행 되었을 때, 거의 100 이면 100, 모두 오류가 나면서 서비스 재시작 실패를 하는데, 주로 다음과 같은 오류가 난다. 빨간색으로 표기한 lastStable 이라는 폴더 외에도 lastStable 이라를 폴더들 관련 ioException 오류들이 표시됩니다.
더보기
hudson.util.HudsonFailedToLoad: org.jvnet.hudson.reactor.ReactorException: java.lang.Error: java.lang.reflect.InvocationTargetException
    at hudson.WebAppMain$3.run(WebAppMain.java:244)
Caused by: org.jvnet.hudson.reactor.ReactorException: java.lang.Error: java.lang.reflect.InvocationTargetException
.....
Caused by: java.lang.Error: java.lang.reflect.InvocationTargetException
.....
Caused by: java.lang.reflect.InvocationTargetException
.....
    ... 8 more
Caused by: java.io.IOException: Tried to treat 'D:\Jenkins\jobs\2. Project_Deploy\modules\etp$etp\lastStable' as a directory, but could not get a listing
    at com.github.mjdetullio.jenkins.plugins.multibranch.TemplateDrivenMultiBranchProject.getConfigFiles(TemplateDrivenMultiBranchProject.java:717)
    ... 23 more

3. 이 상태에서는 Jenkins 서비스가 재시작을 계속 실패한다. 이때, %Jenkins HOME%/jobs 폴더 내 프로젝트 구성 폴더들 안에 있는 lastStable, lastSuccessful 폴더들을 모두 검색하여 삭제해야 한다. 이후 Jenkins 서비스를 재시작을 하면 성공적으로 서비스가 재시작 및 실행 중인 걸 확인 할 수 있다.

한동안은 위의 1,2,3 번 스텝을 slave-node 가 off-line 되는 현상이 있을 때마다 수작업으로 진행 하였는데, 서버 접속 해서 cmd 열고, 서비스 stop 명령어 전달 하고 서비스가 멈추고 나면, 3번 스텝에 언급된 폴더들을 검색하여 삭제 하고, jenkins 서비스의 재시작 누른 후.. 실행을 확인 하게 되는데, 걸리는 시간이 서버 및 네트워크 상태에 따라 족히 15분-30분까지도 걸리는 작업이다. 

정규 배포 날에 해당 문제가 발생하면 이전 버전을 그냥 사용하면서 배포 가능한 시간을 기다릴 수 있지만, 오류패치 배포 등 긴급한 상황인 경우엔 15분도 너무 긴 시간이다. 그래서 클릭 한번으로 서비스 내리고, 폴더들 삭제 하고, 다시 서비스를 올리는 프로그램이 필요했고, 그래서 다음과 같이 만들게 되었다.

출처: https://www.csc.gov.sg/articles/how-to-build-good-software

결론적으로는 프로그램 실행 후 모든 작업이 완료되기까지 소요되는 시간은 평균적으로 2분에서 3분정도 이며 (대부분 미만의 시간이 걸림), 이후 서비스 재시작하기까지 2-3분정도 걸린다. 빠르게 오류 발생 시 대처할 수 있게 되었다.

자 이제부터는 프로그램 코드를 공유 한다. 프로그램 언어는 c# 이며, 사용된 닷넷 버전은 4.0 이다.

서버에서 정기적으로 해당 어플리케이션(.exe) 을 실행 하여 젠킨스 서비스를 재시작하여 불시의 오류를 대비하기 위해 만드는 프로그램이여서, 콘솔앱이며 진행사항을 콘솔 및 로그 파일에 기록한다. - 하지만 불필요하게 서비스를 재시작하기 때문에, 오류 발생 시에만 사용하기로 정하였음.

이제 만들 프로그램은, 기본적으로 app.config 에 들어 있는 위의 정보들을 사용하여, 순차적으로 실행된다. Class 가 2개가 있는데 하나는 ServiceControlCore 라고 이름은 거창하지만, Jenkins 라는 서비스이름 과 타임아웃 시간을 받아 생성되는 객체다. FolderControlCore 역시 이름만 거창할 뿐, 상위 폴더 이름과 삭제할 타겟 폴더 이름을 받아, 폴더 검색, 폴더 확인 및 폴더 삭제를 진행 한다. 

A.     설치된 서버 에서 Windows Services 에 등록되어 있는 특정 서비스 검색 (serviceNameJenkins ) 후 서비스가 실행 중인지 확인한다. bool 값을 리턴받아 다음 단계를 진행한다. 

B.     실행 중인 Jenkins 서비스(serviceName )를 멈춘다. 멈추고(Stop)  20초 timeout 시간을 걸어주는데, 서비스가 멈추는데 걸리는 시간이 대략 최대 20초 정도이다.

C. 프로그램 상단에 생성 시 객체에 지정 해 준 상위 폴더 (upperDirectoryName = %Jenkins HOME% ) 이름 아래에 있는 삭제할 타겟 폴더 (deleteFolderNameList ) 들을 하나 씩 전달하여 타겟 폴더 갯수 만큼 순차적으로 검색 후 삭제를 진행 한다. 

D. Jenkins 서비스 (serviceName=Jenkins)  를 시작한다.( 시작 후 최대 대기 시간 20초)

E.     Log 추가 (NLog 패키지 활용)

NLog 패키지 설정 및 활용에 대해서는 따로 설명은 생략 하므로 잘 작성 된 블로그를 공유한다.

- 참조: https://icodebroker.tistory.com/9402

 

[C#/NLOG] NLOG 사용하기

▶ NLog.config ​ ※ 상기 파일 속성을 아래와 같이 설정한다. 빌드 작업 : (없음) 출력 디렉터리에 복사 : 새 버전이면 복사 ▶ Program.cs using System; using NLog; namespace TestProject { /// /// 프로그램 /// class

icodebroker.tistory.com

더보기
  1. 프로그램 시작
  2. 서비스 확인
  3. 서비스 멈춤 여부
  4. 지운 폴더 리스트 및 개수
  5. 서비스 시작
  6. 그 외 오류

이로써 프로그램은 잘 만들어졌고, 이번 프로그램에서 작성 한 FolderControlCore 와 ServiceControlCore 에 대해서 다음에 좀더 자세히 살펴 보기로 한다.

-끝-

youp-han/Jenkins-Restart: it restarts the running Jenkins Service locally (github.com)

 

GitHub - youp-han/Jenkins-Restart: it restarts the running Jenkins Service locally

it restarts the running Jenkins Service locally. Contribute to youp-han/Jenkins-Restart development by creating an account on GitHub.

github.com

 

반응형
반응형

반응형
반응형
반응형
반응형
반응형
반응형

stackoverflow.com/questions/43687058/how-do-i-include-nuget-packages-in-my-solution-for-net-core-projects

 

How do I include NuGet packages in my solution for .Net Core projects?

With classic .Net projects, if I added a reference to a NuGet package, it would get downloaded to a packages folder and I could check that into source control along with the rest of my code. This

stackoverflow.com

sln 파일이 있는 곳에 NuGet.Config 파일을 만들어 다음 내용을 입력 후, 저장하고, 솔루션을 다시 오픈 하면 된다.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="globalPackagesFolder" value=".\packages" />
  </config>
</configuration>

반응형
반응형

참고: docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/builtin-types/value-tuples

 

튜플 형식 - C# 참조

C# 튜플 알아보기: 관련 데이터 요소를 느슨하게 그룹화하는 데 사용할 수 있는 간단한 데이터 구조

docs.microsoft.com

튜플 테스트

      static (int plus, int minus, int multiply) returnMultiple(int a, int b)
        {

            int plus = a + b;
            int minus = a - b;
            int multiply = a * b;
            return (plus, minus, multiply);
        }

        static void testMethod()
        {
            var a = returnMultiple(3, 2);
            Console.WriteLine(a.minus);
            Console.WriteLine(a.plus);
            Console.WriteLine(a.multiply);
        }

반응형
반응형

    

    using RestSharp;
    using RestSharp.Authenticators;

    namespace User.Model
    {
        
        public class RestCalling
        {
            public string uri { get; set; }
            public string username { get; set; }
            public string password { get; set; }
            public string endPoint { get; set; } //"users/" + userId + "/identities.json"
            public string methodType { get; set; } //PUT, GET, POST, DELETE.

            //GET & Put & Post & Delete
            public string RestClientComm()
            {
                var _client = new RestClient(uri);
                IRestResponse result = null;
                _client.Authenticator = new HttpBasicAuthenticator(username: username, password: password);
                var request = new RestRequest(resource: endPoint, DataFormat.Json);


                switch (methodType)
                {
                    case "PUT": 
                        request.AddParameter("application/json", "\"identity\": {\"value\": \"" + "email@emailAddress" + "\"}}", ParameterType.RequestBody);
                        result = _client.Put(request);
                        break;

                    case "DELETE": 
                        result = _client.Delete(request);
                        break;

                    case "POST": 
                        request.AddParameter("application/json", "{\"identity\": {\"type\": \"email\", \"value\": \"" + "email@emailAddress"+ "\"}", ParameterType.RequestBody);
                        result = _client.Post(request);
                        break;

                    default: //GET
                        result = _client.Get(request);
                        break;

                }

                return result.Content;

            }
        }
    }

반응형
반응형
반응형

+ Recent posts