레이블이 computer인 게시물을 표시합니다. 모든 게시물 표시
레이블이 computer인 게시물을 표시합니다. 모든 게시물 표시

[컴] jenkins 의 plugin list 를 추출하는 법

jenkins plugin 설치 / batch / cli 에서 설치 / 뽑기

jenkins 의 plugin list 를 추출하는 법

jenkins web page 에서 추출하기

https:///script 로 가서

Jenkins.instance.pluginManager.plugins.each{
  plugin -> 
    println ("${plugin.getShortName()}:${plugin.getVersion()}")
}

jenkins cli 로 뽑기

cli 는 다음처럼 받을 수 있다.

curl https:///jnlpJars/jenkins-cli.jar -o jenkins-cli.jar
// get_plugin_list.groovy
def plugins = jenkins.model.Jenkins.instance.getPluginManager().getPlugins()
plugins.each {println "${it.getShortName()}: ${it.getVersion()}"}
java -jar jenkins-cli.jar -s https:// -auth "namh:who1sthegoodman" groovy = < get_plugin_list.groovy >  plugins.txt

jenkins cli 로 plugin 설치

testing - How to install jenkins plugins from command line? - Stack Overflow

java -jar jenkins-cli.jar -s https://inhouse.foodpang.co/ci -auth <username>:<password> install-plugin <plugin_name1> <plugin_name2> ...

Reference

  1. How to get a list of installed Jenkins plugins with name and version pair - Stack Overflow

[컴][유틸] 2024-03, 에디터

hexa editor / hex editor / 괜찮은 hex editor

2024-03, 에디터

See Also

  1. 쿠…sal: [컴] sublime text 2 에서 binary 파일을 text 파일로 열기
  2. 쿠…sal: [컴][유틸] 대용량 파일 뷰어 big size file viewer

[컴] gradle java build 에서 git commit hash id 를 추가

스프링 / 스프링부트 / spring /

gradle java build 에서 git commit hash id 를 추가

com.gorylenko.gradle-git-properties gradle plugin 을 이용할 것이다.

build.gralde

아래처럼 build.gradle 을 설정하자. build 를 하면 build/resources/main/git.properties 가 만들어진다.

plugins {
  id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
...
gitProperties {
    keys = ['git.branch','git.commit.id','git.commit.time']
    customProperty 'greeting', 'Hello' // expression
    // Customize file name (could be a file name or a relative file path below gitPropertiesResourceDir dir)
    gitPropertiesName = "my-git-file.properties"
    dotGitDirectory = file("${project.rootDir}/.git") # 정의하지 않으면, 자동으로 .git folder를 찾는다.
}

git.properties

위에서 gitPropertiesName 로 properties file 의 이름을 변경했기에, build/resources/main/my-git-file.properties 가 만들어진다.

my-git-file.properties 의 내용은 다음과 같다.

// build/resources/main/my-git-file.properties
git.branch=mybranch_name
git.commit.id=0c5da9f4f7312bb6c02f21c47ae129b31a006046
git.commit.time=2024-03-10T11\:18\:37+0900
greeting=Hello

jar 에서 위치

그리고 이것은 gradlew build 를 할 때 아래 경로에 들어가게 된다.

  • myjar-0.0.1.jar\BOOT-INF\classes\git.properties

SpringBoot

[컴] amazone 의 Correctto 17

 

amazone 의 Correctto 17

아마존에서 제공하는 OpenJDK 17 로 보면 된다. LTS(Long Term Support) 를 지원한다.

curl -LO https://corretto.aws/downloads/latest/amazon-corretto-17-x64-linux-jdk.tar.gz

아래 링크에 가면, deb, rpm 등도 다운로드 받을 수 있다.

[컴] MySql virtual column

mariadb 마리아db /

MySql virtual column

ALTER TABLE t1 ADD COLUMN c2 INT GENERATED ALWAYS AS (c1 + 1) STORED;
ALTER TABLE t1 ADD COLUMN c2 INT GENERATED ALWAYS AS (c1 + 1) VIRTUAL;

다른 table의 column을 이용하려면, view를 만드는 것도 방법이다.

Reference

  1. Generated (Virtual and Persistent/Stored) Columns - MariaDB Knowledge Base
  2. mysql - Stored/Virtual Generated Column- Pros/Cons/Best Practices? - Stack Overflow

[컴] SpringBoot 3.x 의 logging 설정

logback config / springboot log configuration / log config / spring log / 기간 설정

SpringBoot 3.x 의 logging 설정

spring-boot-starter-web을 사용한다면 logback 이 dependency 에 걸려있어서 자동으로 추가된다.

좀 더 자세한 logback option 의 설명

logback.rollingpolicy.max-history 에 대한 설명

TimeBasedRollingPolicy 를 사용한다면, max-history 는 ’며칠의 log를 보관하는 지를 결정’하는 설정이 된다고 한다.

totalSizeCap 을 설정해놓는 것이 disk usage 를 관리하는데 도움이 될 것이라고 한다.

[[컴] kafka app log 주기적으로 삭제

remove kakfka application log / kafka stream log / 자동 삭제

kafka app log 주기적으로 삭제

kafka log 라고 하면 대체로 data 에서 사용하는 log 로 검색된다. 여기선 kafka app 이 찍는 log 를 이야기 한다. 이것은 log4j 로 되어 있어서 log4j 설정을 잡아주면 된다. MaxFileSize, MaxBackupIndex 를 사용하면 된다.

  • MaxFileSize
  • MaxBackupIndex
log4j.rootLogger=INFO, stdout, kafkaAppender

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d] %p %m (%c)%n

log4j.appender.kafkaAppender=org.apache.log4j.RollingFileAppender
log4j.appender.kafkaAppender.File=${kafka.logs.dir}/server.log
log4j.appender.kafkaAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.kafkaAppender.layout.ConversionPattern=[%d] %p %m (%c)%n
log4j.appender.kafkaAppender.MaxFileSize=500MB
log4j.appender.kafkaAppender.MaxBackupIndex=5
...

DailyRollingFileAppender 에서 사용은 주의하자.

DailyRollingFileAppender 에서 MaxBackupIndex = 3 를 사용한다고 해도, 이것이 3일치 log를 보관하는 것을 이야기하는 것은 아니다. 같은 이름의 log에 대해서 backup 을 3개까지 보관가능하다는 뜻이다.

log.2009-11-07.1, log.2009-11-07.2, log.2009-11-07.3 을 보관한다는 이야기다.

Reference

  1. Kafka logs are not deleted - Ops - Confluent Community
  2. Logging · The Internals of Apache Kafka

[컴] 80열은 지키지 않아도 괜찮다.

80 cols / 80 columns /

80열은 지키지 않아도 괜찮다.

개인적으로도 여러가지 생각이 들었지만, 그래도 80열을 맞추는 것이 가독성을 더 좋게 할 것이라 생각했다. 예를 들면, 신문의 타이포그래피를 봐도 그렇지만, width를 일정수준으로 맞춰놓는다. 이것이 확실히 한눈에 한줄을 보기 쉽게하고, 빠르게 읽을 수 있게 해준다.

이런 장점이 있지만, code 는 그것과는 조금 다르게 보는 것이 맞을 듯 하다. 필자도 때론 한줄에 적는것이 더 좋을 것 같은 코드라인을 본다. 하지만 어떻게 하면 80을 맞출 수 있을까 생각한다.

나만 그러고 있는 듯 하지만, 더이상 80열을 심각하게 고려할 필요는 없을 듯 하다. 유명한 개발자가 한 이야기라 더 설득력이 있게 들린다. (물론 리누스는 리눅스 커널코드에 대한 이야기를 한 것이긴 하다.)

이것때문에 사내 좀 더 젊은 개발자에게 물어본 적이 있는데, 80열을 맞춰야 된다는 생각을 가진 분들은 없더라.^^;;;

간략하게 이야기하자면, 더이상 우리는 작은 터미널화면을 사용하던 시대에 살지 않으며, 더이상 그것을 고려할 이유가 없다고 이야기한다. 80열 터머널을 가진 유저는 wrapping 기능을 이용하면 그만이라고 설명한다.

끊임없이 변한다. 그래서 꾸준히 학습해야 한다. IT세상은 지루할 틈은 없어보인다.

Reference

  1. 80-characters-per-line limits should be terminal, says Linux kernel chief Linus Torvalds • The Register

[컴] spring에서 test container 사용시간 단축하기

 

test container / testcontainer / 스프링에서 / 스프링부트 / springboot / 스프링

spring에서 test container 사용시간 단축하기

test container 를 이용해서 test 를 하면, container 를 load 하는 시간이 오래걸린다. 개인적으로 ssd 가 아닌 hdd 에서 동작하도록 해서 그런지 더 실행시간이 오래걸렸다.

그래서 test 를 자주 하려면, 최대한 test container 의 실행을 줄이는 것이 좋다. 즉, 덜 자주 unload , load 를 하는 것이 낫다.

container 를 1번만 실행

Testcontainer 를 사용하면 test class에 @Testcontainers를 사용하게 된다. 이것은 매 class마다 container 를 실행하게 된다.

대체로 test container 를 이용해서 test 를 하면, container 를 load 하는 시간이 오래걸린다. 개인적으로 ssd 가 아닌 hdd 에서 동작하도록 해서 그런지 더 실행시간이 오래걸렸다.

때문에, test 를 자주 하려면, 최대한 test container 의 실행을 줄이는 것이 좋다. 즉, 덜 자주 unload , load 를 하는 것이 낫다.

그래서 이것을 우리는 이것을 전체 test 에서 1번만 실행하게 할 것이다.

위 글에도 나와 있지만 static variable 에 할당하는 것으로 container 의 생성을 1번으로 만든다.

datasource 의 설정

이것은 ApplicationContextInitializer 를 이용한다.

특정 profile 에서는 현재 띄워져있는 container 를 사용하도록 한다

testcontainer를 부하를 줄이려 1번만 load 한다고 해도, TDD 등을 할때는 속도가 엄청 느리다. 계속 unload/load 가 이뤄지기 때문에 빠른 개발이 어렵다.

그래서 build 시점에는 testcontainer 를 사용해서 test 를 하지만, 개발을 할때는 현재 띄워져 있는 container에 접속해서 test 할 수 있도록 했다.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = TestcontainersInitializer.class)
class FishApplicationTests {
}
...


public class TestcontainersInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private static final String MIGRATION_LOCATION = "filesystem:db/migration";
    public static final MariaDBContainer<?> mariaDB = new MariaDBContainer<>("mariadb:10.6")
            .withDatabaseName("myapp")
            .withUsername("myapp-user")
            .withUrlParam("useBulkStmts", "false")
            .withPassword("strong-password")
            .withReuse(true);

    public static final LocalStackContainer localStack = new LocalStackContainer(
            DockerImageName.parse("localstack/localstack"))
            .withServices(LocalStackContainer.Service.S3)
            .withReuse(true);

    public static final KafkaContainer kafka = new KafkaContainer(
            DockerImageName.parse("confluentinc/cp-kafka:7.5.0"))
            .withReuse(true);

    /*
     * Static block runs before Spring Boot starts the application context.
     */

    @Override
    public void initialize(@NotNull ConfigurableApplicationContext ctx) {
        // if system.property active profile is test, do not start containers
        final String EXCLUDE_PROFILE = "testnocontainer";
        var activeProfiles = ctx.getEnvironment().getActiveProfiles();
        if (activeProfiles.length <= 0 || !activeProfiles[0].equals(EXCLUDE_PROFILE)) {
            // if active profile is NOT 'testnocontainer'

            // 만약 여러개의 test class 를 실행하면 이부분은 당연히 여러번 실행된다. 하지만 괜찮다.
            // static 이라서 여러번 실행되지 않았다.

            /**
             * This routine runs multiple times, but due to the use of the static variables,
             * it only works once
             */
            /*
             * deepStart() is used to start containers in parallel.
             */
            Startables.deepStart(mariaDB, localStack, kafka).join();
            
            runMigrations(); // run flyway

            // 여기를 실행하지 않는 profile 은 application.xml 의 datasource 쪽을 바라보게 된다.
            // 그러므로 datasource setting 을 해놔야 한다.
            TestPropertyValues.of("spring.datasource.url=" + mariaDB.getJdbcUrl())
                .and("spring.datasource.username=" + mariaDB.getUsername())
                .and("spring.datasource.password=" + mariaDB.getPassword())
                .and("spring.kafka.bootstrap-servers=" + kafka.getBootstrapServers())
                .applyTo(ctx);
        }
    }

    private static void runMigrations() {
        Flyway.configure()
                .dataSource(mariaDB.getJdbcUrl(), mariaDB.getUsername(),
                        mariaDB.getPassword())
                .locations(MIGRATION_LOCATION)
                .schemas(mariaDB.getDatabaseName())
                .baselineOnMigrate(true)
                .load().migrate();
    }
}

See Also

  1. 쿠…sal: [컴] Spring Test 에서 @Sql 을 code 로

[컴] AI 에서 어떻게 model 을 디자인 하는 것일까?

 

AI 에서 어떻게 model 을 디자인 하는 것일까?

아래 영상을 보고 간단하게 keras 를 이용해서 ai model 을 만들어볼 수 있다.

  • Make Your First AI in 15 Minutes with Python - YouTube
  • 에러
    • ValueError: Input 0 of layer "sequential_1" is incompatible with the layer: expected shape=(None, 455, 30), found shape=(None, 30) 와 같은 에러가 발생하는데 code에서 model.add(tf.keras.layers.Dense(256, input_shape=x_train.shape[1:], activation='sigmoid')) 로 변경하면 된다. x_train.shape 대신 x_train.shape[1:]를 사용하는 것이다.

여기서 궁금중은 그러면 model 을 만들때 사용한 layer를 어떤 기준으로 추가했느냐이다. 그리고 그 layer에 사용한 activation function 은 어떤 기준으로 선택했는가 이다.

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(256, input_shape=x_train.shape, activation='sigmoid'))
model.add(tf.keras.layers.Dense(256, activation='sigmoid'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))

그럼 어떻게 model 을 만들까?

이것에 대한 대답을 다음 글에서 확인할 수 있을 듯 하다.

이글은 deep learning 의 성능을 향상시키는 방법을 이야기하는데, 여러가지 방법이 있다.

  • 데이터양을 증가시키는 방법
  • 데이터를 normalize 하는 법
  • 데이터를 시각화해서 모양을 봐보라, 그러면 이것이 가우스분포같은지, log분포같은지등을 보고, 필요한 변환을 해볼 수 있다.
  • feature selection
  • 문제를 구성하는 방법을 변경해봐라
  • 여러 알고리즘을 통한 향상
    • 선택한 알고리즘이 best가 아닐 수 있다. linear methods, tree methods, instance methods, 다른 neural network methods 들로 평가해봐라.
    • 논문등 다른 사람들이 했던 비슷한 문제들을 찾아서 아이디어를 얻어라(리서치를 해라)
    • 샘플링한 dataset을 다시 잘 sampling 한다. 예를 들어 train/test 로 나눴다면, train 에 해당하는 dataset이 문제의 대표성을 띠는지 등. 또는 작은 dataset을 사용하고, 그에 맞는 model을 선택해서 테스트해보고 큰 dataset으로 확장해 볼 수도 있다.
  • 알고리즘 튜닝을 통한 향상
    • 진단, overfitting인지 underfitting인지
    • 가중치 초기화
    • 학습률을 조정
    • activation function
    • network topology , 여러가지 구성을 테스트해본다. 1개의 많은 newrons를 갖는 hidden layer를 시도하던지, layer당 적은수의 neuron들을 갖는 deep network 를 시도하던지, 이 2개를 전부해보던지등.
    • batches and Epochs, batch size를 변경하는 것은 gradient를 정의하고, weight들을 얼마나 자주 update하는지를 정한다. epoch는 배치마다 ‘network 에 노출되는 전체 dataset’ 이다.
    • 정규화, overfitting을 억제하는 좋은 방법이다. dropout이라는 정규화기술도 있다.
    • 최정화와 손실, 이전에 최적화는 ‘확률적 경사하강법(stochastic gradient descnet)’ 였지만, 이젠 많은 optimizer들이 있다.
    • 빠른 정지(Early Stopping), 성과가 저하되기 시작하면 학습을 중단한다. 그리고 다른 sample을 만들던지 하는등으로 시간을 절약할 수 있다.

[컴] Docker 의 DockerCli.exe -SwitchDaemon

SwitchDaemon 은 무슨 용도 /

Docker 의 DockerCli.exe -SwitchDaemon

ref. 2 를 보면, linux 에서 windows container 를 실행할 수 없다.

windows 에서는 WSL2 를 제공하기 때문에, linux container 를 실행할 수 있고, windows 이기에 windows container도 실행 가능하다. 그래서 ref. 2 에 보면, linux container와 windows container 를 동시에 실행하는 것도 가능하다.

참고로, Docker for windows에는 windows container를 위해선 WindowsEngine을 사용하고, linux container 를 위해선 LinuxEngine을 사용한다.

engine 변경 방법

이 때 engine 을 변경하는 방법이 DockerCli.exe -SwitchDaemon 이다.

C:\Program Files\Docker\Docker
DockerCli.exe -SwitchDaemon

특정 engine 으로 변환하려면 다음처럼 하면 된다.

DockerCli.exe -SwitchWindowsEngine
DockerCli.exe -SwitchLinuxEngine

References

  1. Run Linux and Windows Containers on Windows 10
  2. docker - Can Windows containers be hosted on Linux? - Stack Overflow
  3. Docker ❤️ WSL 2 - The Future of Docker Desktop for Windows | Docker

[컴] Spring Test 에서 @Sql 을 code 로

springboot test / junit / unittest/ /통합테스트 / .sql / query / 쿼리실행 / 초기 데이터 세팅 / setup / @Sql 대신 사용

Spring Test 에서 @Sql 을 code 로

아래와 같은 annotation 을

@JooqTest
@Sql({"classpath:myquery1.sql", "classpath:myquery2.sql"})
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTests {
    ...
}

아래처럼 변경했다. 아래는 특정 profile 이 아닐때만 sql 을 실행하도록 했다.

@JooqTest
// @Sql({"classpath:myquery1.sql", "classpath:myquery2.sql"})
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTests {

    // require: @JooqTest
    @Autowired
    DSLContext ctx;
    @Autowired
    DataSource dataSource;
    @Autowired
    Environment env;

    ProductStatusBgJobProcessor backgroundJobProcessor;

    @BeforeAll
    void beforeAll() {
        runSqlInitData(dataSource);
    }

    @BeforeEach
    void setUp() {

        ...
    }

    @Test
    void myTest1() throws Exception {

        ...

    }

    private void runSqlInitData(DataSource dataSource) {
        final String EXCLUDE_PROFILE = "testnocontainer";
        var activeProfiles = env.getActiveProfiles();
        if (activeProfiles.length <= 0 || !activeProfiles[0].equals(EXCLUDE_PROFILE)) {
            // when not 'testnocontainer' profile
            ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
            populator.addScripts(
                    new ClassPathResource("myquery1.sql"),
                    new ClassPathResource("myquery2.sql"));
            populator.setSeparator(";");
            populator.execute(dataSource);
        }
    }
}

Spring, Integration Test 에서 sql file을 실행하기

sql script 를 실행하기 위해 다음 4개의 함수를 사용할 수 있다.

  • org.springframework.jdbc.datasource.init.ScriptUtils: SQL 스크립트가 parse되고 실행되는 방법을 완전히 제어할 때 사용
  • org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
    • 내부적으로 ScriptUtils 를 사용
  • org.springframework.test.context.junit4.[AbstractTransactionalJUnit4SpringContextTests](https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/support-classes.html#testcontext-support-classes-junit4)
    • 내부적으로 ResourceDatabasePopulator를 사용
  • org.springframework.test.context.testng.[AbstractTransactionalTestNGSpringContextTests](https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/support-classes.html#testcontext-support-classes-testng)
    • 내부적으로 ResourceDatabasePopulator를 사용

Reference

  1. Executing SQL Scripts :: Spring Framework

[컴] SpringBoot v3 에서 openapi v2 사용

javadoc / 자동 문서 / swagger / api 문서 작성 /

SpringBoot v3 에서 openapi v2 사용

gradle 사용시 spring boot 에서 openapi spec의 문서를 만드려면 아래 build.gradle 처럼 springdoc-openapi-starter-webmvc-ui 를 추가하면 된다.

  • implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

springboot v3 을 사용한다면 springdoc-openapi 2.x 를 사용해야 한다. springdoc-openapi-starter-webmvc-uispringdoc-openapi-ui의 openapi-v2 이다.

// build.gradle
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.1'
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.nsm'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
}

tasks.named('test') {
    useJUnitPlatform()
}

test

내 springBoot server가 localhost:8080 에 떠있는 경우, 다음 경로로 가면 api 문서 화면이 보인다.

json format은

disable

다음 옵션 2개를 꺼주면 된다.

springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false

문서작성 annotation

일부는 자동으로 만들어주지만, 정확하지 않은 값으로 만들어준다. 명시적으로 api 문서에 값을 넣을때는 annotation 을 활용할 수 있다.

아래를 참고하면 된다.

다만, @RequestBody의 경우 spring 의 annotation 과 겹쳐서 @io.swagger.v3.oas.annotations.parameters.RequestBody 등으로 사용해야 할 수 있다.

@PostMapping
@Operation(summary = "Create a User", description = "This can only be done by the logged in user.")
ResponseEntity<MyResponse> createUser(
        @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Created User object", 
          required = true, content = @Content(schema = @Schema(implementation = MyPostBody.class))) 
        @Valid @RequestBody MyPostBody user) {
    return ResponseEntity.status(HttpStatus.CREATED)
            .body(userService.createOne(user));
}

Reference

  1. OpenAPI 3 Library for spring-boot

[컴] 구글 워크스페이스 특정계정의 2단계인증 중지 방법

구글 계정/ 구글 어드민 / google workspace / google gsuite /

구글 워크스페이스 특정계정의 2단계인증 중지 방법

2024-01-01 화면 기준

  1. https://admin.google.com/
  2. 메뉴 –> 디렉토리 –> 사용자
  3. 수정하기를 원하는 사용자의 이름을 클릭 –> 상세화면이 보인다.
  4. ‘보안’ 부분으로 간다. 여기서 확장(expand) icon 클릭
  5. ‘본인 확인 요청’ 클릭
  6. 사용 중지

References

  1. 본인 확인 요청, 2단계 인증, 로그인 관련 문제 해결하기 - Google Workspace 관리자 고객센터
  2. 사용자의 본인 확인 요청 일시적으로 사용 중지하기 - Google Workspace 관리자 고객센터

[컴] 구글 클라우드에 만들어 놓은 project 의 owner 계정이 사라지면 project 는 같이 지워질까?

구글 클라우드에 만들어 놓은 project 의 owner 계정이 사라지면 project 는 같이 지워질까?

google cloud(https://console.cloud.google.com/) 에 만들어 놓은 project 의 owner 계정이 사라지면 project 는 같이 지워질까?

개인 계정인 경우는 그렇다.

그러나 google workspace 같은 경우라면 다르다.

  • 계정(account) 가 organization(조직) 에 속해있으면, project 는 organization 에 속하게 됨.
  • 그래서 organization 의 admin 이 접속할 수 있게 됨.
  • IAM page 가서 새로운 owner 를 할당할 수 있다.

Reference

  1. What happens when we delete the google account of a project owner? - Stack Overflow

[컴] spring boot project 를 vscode 에서 실행하기

springboot / vscode 에서 java 사용 / --debug-jvm / unittest system.out / stdout 출력

spring boot project 를 vscode 에서 실행하기

잠깐 써본 소감은 'Language Support for Java' 의 memory 를 max 2G까지 올렸는데, 그래서인지 메모리를 많이 잡아먹었다. 그러나, IntelliJ를 사용할때와 비슷한 수준이었다.

설치한 vscode extension

‘Language Support for Java’ 에 대한 java home 설정

여기선 workspace setting 을 변경했다.

// myproj.code-workspace
{
    "folders": [
        {
            "path": ".."
        }
    ],
    "settings": {
        "java.jdt.ls.java.home": "d:\\a\\appss\\jdk-17.0.6.10-hotspot"
    }
}

gradle extension 에서 실행

아래 그림처럼 gradle 의 task 를 실행할 수 있다. 여기서 debugger 를 run 하거나, 그냥 run 하거나 할 수 있다.

vscode 화면

개별 class test 시 debug mode

아직은 gradle extension 에서 개별 class의 test 에 대한 debug mode run 은 지원이 안된다.

그래서 다음과 같은 방법으로 gradle test 에 debugger 를 붙일 수 있다.

  1. vscode 내부 터미널에서 다음처럼 gradle test 를 실행하고,
gradlew test --tests co.my.pro.MyTests --debug-jvm
  1. 아래처럼 launch.json을 설정해서 debugger를 실행(f5)시킨다.
// launch.json
{
    "version": "0.2.0",
    "configurations": [
        
        {
            "type": "java",
            "request": "attach",
            "name": "Attach by Process ID",
            "processId": "${command:PickJavaProcess}"
        }
    ]
}
  1. 그러면 process 를 선택하면 된다.

--debug-jvm : Testing in Java & JVM projects

console log

testLogging.showStandardStreams = true 을 해주면, log 가 stdout 으로 찍힌다.

events=["passed", "failed", "skipped", "standard_out", "standard_error"]

로 설정하는 것은

events=["passed", "failed", "skipped"]
showStandardStreams = true

과 같다. showStandardStreamsevents=["standard_out", "standard_error"] 과 같다. 위와 같이 설정하면 2개가 동시에 적용된다.


test {
    useJUnitPlatform()

    // set systemProperties with default value "spring.profiles.active=test"
    systemProperties = System.properties
    if (!systemProperties.containsKey('spring.profiles.active')) {
        systemProperty("spring.profiles.active", "test")
    }

    testLogging { 
        events=["passed", "failed", "skipped", "standard_out", "standard_error"]
        // events=["passed", "failed", "skipped"]
        // showStandardStreams = true
    }
}

See Also

  1. Run and Debug Java in Visual Studio Code
  2. 쿠…sal: [컴][자바] vscode 에서 java 사용하기, 2017-02
  3. Debugging doesn't work · Issue #876 · microsoft/vscode-gradle · GitHub

[컴][웹] 2개의 다른 domain 에서 서버가 같은 상위 domain 을 사용하는 cookie 를 생성하도록 경우, 브라우저의 credential: 'include' 동작

만약 a.domain.net, b.domain.net 이 모두 Domain을 .domain.net 으로 해서 Set-Cookie 를 날리는 상황을 가정해보자.

  • a.domain.net : Set-Cookie: session=11111111111; path=/; domain=.domain.net; HttpOnly

  • b.domain.net : Set-Cookie: session=22222222222; path=/; domain=.domain.net; HttpOnly

  • A라는 사이트에서 login 은 해서 cookie 가 만들어졌다. 이때 credential 을 include 하면 이 cookie 가 request 시점에 날라간다.

  • 이 때 B라는 사이트에서 login을 한다. 그런데 같은 domain 에 대해서 만들기 때문에, A 라는 사이트에서 사용하던 cookie 가 browser에서 지워지고, 새롭게 B site 에서 사용할 cookie 가 만들어진다.

  • cookie 는 도메인 별로 unique 하게 존재하지만, 이것을 해당 domain 외의 domain 에서 access 하는 것 또한 same-origin policy 를 따라야 해서, 다른 site A에서 credential(cookie)이 없는 채로 날라간다.

See Also

  1. http - Share cookies between subdomain and domain - Stack Overflow
  2. https://setcookie.net/ : 여기서 Set-Cookie 의 domain설정을 해서 테스트해 볼 수 있다.

[컴] backbone network 란?

백본망 / 백본은 뭔가?

backbone network 란?

일반적으로 ref.1 에 나와있듯이 ’주요 노드(primary nodes)를 연결하는 고용량 통신 시설(high capacity communication facilities)’을 가리키는 용어이다.

기본적으로 backbone network 는 개념적인 이야기다. 그러므로 일반적인 뜻보다는 좀 더 작은 용량의 시설도 sub-network들을 연결한다면 백본망이라 부를 수 있다.

만약 내가 ISP 로 부터 인터넷 선을 하나 할당받고, 이것을 허브를 이용해서 사무실 2개에 대해 각각 케이블을 뽑고, 그 케이블마다 공유기에 연결해서 각각 network 를 구성했다고 하자. 그렇다면 나의 백본망은 이 NAT 와 각 사무실로 뻗어나가는 2개의 유선일 것이다.

통신사업자(ISP) 의 백본

ISP 의 백본은 우리가 일반적으로 생각하는 백본이라고 생각하면 될 것 같다. 다음 기사를 통해 대략적으로 어떻게 구성되어 있는지 확인해 볼 수 있다.

See Also

  1. Backbone network - Wikipedia
  2. 백본망 코어망 라우터 게이트웨이 개념

[컴] Java Spring JobRunr

 

스프링 / 스케쥴러 / scheduler / celery

Java Spring JobRunr

  • job 을 다른 background thread에서 수행한다. 그래서 web request 가 block 되지 않는다.
  • java 8 lambda 를 분석해서 json 으로 serialize한다. 이 것을 db 에 저장한다.
  • 많은 job 들이 만들어져서, server 가 그 load를 처리할 수 없게 됐을때, app instance 를 늘리면, JobRunr이 자동으로 그 job 을 분산시킨다.(scale horizontally)
  • retry 는 자동으로 이뤄지는데, 이때 exponential back-off policy 를 사용한다.
  • 모든 job들을 monitor 하는 built-in dashboard 가 있다.
  • 성공한 job 들을 일정 시간이 지나면 자동으로 지워지게 할 수 있다. 이 일정시간을 설정할 수 있다.
  • Real time trigger processing · jobrunr/jobrunr · Discussion #442 · GitHub : 5초 단위의 pollingTimeInterval 을 갖는다. 그래서 그보다 낮은 시간간격으로 수행해야 하는 job 들의 경우 문제가 있다. 그리고 정확히 간격이 맞지 않는다면, 특정 scheduled job 이 정해진 시간보다 먼저 실행될 수도 있다? 
  • Background Job Poll Interval time | github : pollingTimeInterval 의 기본값은 15초
  • Important remarks | Recurring jobs · JobRunr

port 설정

기본은 8000 이다. localhost:8000/dashboard 로 가면 JobRunr 의 dashboard를 확인할 수 있다. 다음처럼 config file 에서 변경할 수 있다.

org.jobrunr.dashboard.enabled=true 
org.jobrunr.dashboard.port=8000

매분단위 job 을 실행한 개인적인 경험, jobrunr 6.2.3

매분마다 도는 job 을 설정해놨다. 그러고 나서, 보니 같은 시점에 2개가 실행됐다. 그래서 db 의 jobrunr_jobs 에서 확인을 해보니, 같은 시간에 2번이 실행됐다.

created_at 을 보니, 매 분마다 실행시간이 조금씩 밀렸다. 대략 0.08s~0.09s 씩 늦어졌다. 그래서 결국 같은 시점에 2번이 실행되는 상황이 왔다.

위의 5초단위의 pollingTimeInterval 과 어느정도 상관관계가 있는 듯도 싶다. 만약 항상 40~50초 시점에 trigger 가 발생한다면, job 내에서 시간을 보정해서 사용하는 것도 방법일 듯 하다.

같은 ‘분’(minute)에 실행된 job 들을 확인하기 위한 query

-- 같은 '분'(minute)에 실행된 job 들
SELECT * FROM (
    SELECT count(his) cnt, t1.* FROM (
        SELECT DATE_FORMAT(createdAt, '%j %H:%i') AS his, DATE_FORMAT(createdAt, '%H:%i:%S.%f'), createdAt, updatedAt  
        FROM jobrunr_jobs 
        WHERE recurringJobId 
          IN('myjob.MyJobBackgroundJobProcessor.runEveryMinuteExample()')
        ORDER BY createdAt DESC
    ) AS t1 
GROUP BY t1.his
) AS tt1 WHERE cnt > 1
;

이슈가 있던 때의 createdAt 과 updatedAt 값들

createdAt updatedAt
2024-02-13 04:21:59.615 2024-02-13 04:21:59.696
2024-02-13 04:22:59.715 2024-02-13 04:22:59.793
2024-02-13 04:23:59.812 2024-02-13 04:23:59.880
2024-02-13 04:24:59.904 2024-02-13 04:24:59.988
2024-02-13 04:26:00.016 2024-02-13 04:26:00.393
2024-02-13 04:26:45.418 2024-02-13 04:26:45.494


2024-02-13 06:39:59.635 2024-02-13 06:39:59.706
2024-02-13 06:40:59.726 2024-02-13 06:40:59.793
2024-02-13 06:41:59.812 2024-02-13 06:41:59.885
2024-02-13 06:42:59.910 2024-02-13 06:42:59.976
2024-02-13 06:44:00.001 2024-02-13 06:44:00.327
2024-02-13 06:44:45.314 2024-02-13 06:44:45.358


2024-02-13 08:54:59.536 2024-02-13 08:54:59.603
2024-02-13 08:55:59.625 2024-02-13 08:55:59.695
2024-02-13 08:56:59.723 2024-02-13 08:56:59.804
2024-02-13 08:57:59.820 2024-02-13 08:57:59.887
2024-02-13 08:58:59.913 2024-02-13 08:58:59.980
2024-02-13 09:00:00.020 2024-02-13 09:00:03.025
2024-02-13 09:00:46.289 2024-02-13 09:00:46.723

cron time 설정시 주의

만약 다음처럼 정의를 하면,

@Recurring(cron = "*/10 * * * *", zoneId = "Asia/Seoul")

job 은 다음처럼 10분 근처에서 실행한다. 30분에 대한 trigger 가 29:54 쯤에 발생한다.

createdAt updatedAt
2024-02-17 07:29:54.207 2024-02-17 07:29:54.239
2024-02-17 07:19:53.956 2024-02-17 07:19:53.983
2024-02-17 07:09:53.689 2024-02-17 07:09:53.798

Reference

  1. Background Jobs in Spring with JobRunr | Baeldung

Start recurring jobs multiple times? · jobrunr/jobrunr · Discussion #755 · GitHub

[컴] client-side web app 을 위한 OAuth 2.0

google cloud credential / api credential / access token

client-side web app 을 위한 OAuth 2.0

OAuth 2.0 은 유저들이 application 과 특정data 를 공유할 수 있게 해준다. 공유하면서도 그들의 user명과 비밀번호와 다른 개인정보를 노출하지 않는다.

예를 들어 OAuth 2.0 은 user의 Google Drive에 file 을 저장하기 위해 그 해당 user로 부터 permission(허락)을 획득하게 된다.

OAuth 2.0 flow 는 implicit grant flow (암묵적 허락 흐름)라고 부른다. 이것은 ’user 가 application 에 있을때만 API들에 접근’하는 application들을 위해 만들어졌다. 이 application들은 기밀정보(confidential information)를 저장해 놓을 수 없다.

me: 그래서 access token 만 처음에 받아와서 사용하게 된다. app 등은 Authorization Code 를 받아온 후에 다시 access token 을 받는다. 다음 글들을 읽어보면 된다. Using OAuth 2.0 for Web Server Applications 를 봐도 알 수 있는데, 이것은 confidential information 을 저장해 놓고 사용하는 app을 위해 design 됐다고 나와 있다.

동작

이 flow에서, app 은 query parameter를 이용하는 Google URL 을 연다. 이 query parameter 는 app 을 구별하고, app 이 필요한 API 접근의 종류를 구별하는 값을 갖고 있다.

현재 브라우저 window 에서 이 URL 을 열거나 popup 으로 열 수 있다.

user 는 Google 에서 인증하고, app이 요청하는 permission 들을 grant 해주게 된다. Google 은 그리고 나서 user 를 app 으로 다시 redirect 시킨다. 이 때 access token 와 함께 redirect 시킨다. app 은 이 access token 을 확인(verify)하고, API 요청을 만들때 사용된다.

Goolge OAuth 2.0 server

Google API들에 access 하기 위해서 OAuth 2.0 을 사용하는 모든 application은 authorization credential들을 가져야만 한다. 이 authorization credential 은 Google 의 OAuth 2.0 server 가 application 을 판별할 수 있게 해준다.

이 credential id 는 다음 link 에서 만들 수 있다.

여기서 authorized JavaSCript origins 를 설정하게 된다. 이 설정된 origin 에서 보내는 request 만 accept 하는 것이다.

auth code flow 를 사용하자.

위의 글의 내용은 요즘 브라우저에서 3rd party cookie 를 없애려는 움직임이 있다. 그런 이유로 implicit grant flow 는 더이상 auth 를 하는 방법으로 적절치 않다는 이야기다.

See Also

  1. 쿠…sal: [컴][웹] OAuth 2.0